Bug 1249802 - Merge closed branch head into default
authorGregory Szorc <gps@mozilla.com>
Fri, 03 Jun 2016 14:29:16 -0700
changeset 324867 9f90f4632417521f101a227e1ae9b3d1e7c1a070
parent 324866 424462cbaec494f8d25ca5317d98b3e213144310 (diff)
parent 324684 e19397d89243ad3e88c4a39b9ae4bdfce5d20bb7 (current diff)
child 324868 7d5e6c0d230d432936cbf7063ace3c22a11bd93e
push id6046
push usergszorc@mozilla.com
push dateFri, 03 Jun 2016 21:34:27 +0000
treeherdermozilla-beta@a86835580095 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1249802
milestone47.0
Bug 1249802 - Merge closed branch head into default
--- a/.eslintignore
+++ b/.eslintignore
@@ -34,18 +34,16 @@ modules/**
 mozglue/**
 netwerk/**
 nsprpub/**
 other-licenses/**
 parser/**
 probes/**
 python/**
 rdf/**
-security/**
-services/**
 startupcache/**
 testing/**
 tools/**
 uriloader/**
 view/**
 webapprt/**
 widget/**
 xpcom/**
@@ -59,69 +57,83 @@ 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/customizableui/**
 browser/components/downloads/**
 browser/components/feeds/**
-browser/components/migration/**
-browser/components/*.js
-browser/components/places/**
-browser/components/pocket/**
 browser/components/preferences/**
 browser/components/privatebrowsing/**
 browser/components/sessionstore/**
 browser/components/shell/**
 browser/components/tabview/**
 browser/components/translation/**
-browser/components/uitour/**
-browser/experiments/**
 browser/extensions/pdfjs/**
-browser/extensions/shumway/**
-browser/fuel/**
+browser/extensions/pocket/content/panels/js/vendor/**
 browser/locales/**
-browser/modules/**
-
-# Loop specific exclusions
 
 # Ignore all of loop since it is imported from github and checked at source.
 browser/extensions/loop/**
 
 # devtools/ exclusions
-# Ignore d3
-devtools/client/shared/d3.js
-devtools/client/webaudioeditor/lib/dagre-d3.js
+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 codemirror
-devtools/client/sourceeditor/codemirror/*.js
-devtools/client/sourceeditor/codemirror/**/*.js
-devtools/client/sourceeditor/test/codemirror/*
-
-# Ignore jquery test libs
-devtools/client/markupview/test/lib_*
-
-# Ignore pre-processed files
+# 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 various libs
+# 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
@@ -132,47 +144,46 @@ 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
 
-# es7 proposed: array comprehensions
-#   https://github.com/eslint/espree/issues/125
-mobile/android/modules/WebappManager.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/**
-toolkit/components/passwordmgr/**
-toolkit/components/places/**
 
 # Uses preprocessing
-toolkit/content/contentAreaUtils.js
+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/modules/SessionRecorder.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,9 +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
@@ -99,18 +102,21 @@ GPATH
 # 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.
@@ -118,9 +124,11 @@ GPATH
 # 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
@@ -226,11 +226,58 @@ 6a7547e4a0f0e213bb8487c773e16543cbea8c73
 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
-629b622542d0b12483ad999cda5eb2c5b02f6b86 FENNEC_45_0b9_RELEASE
-bf182675fd0584774210ca1cc092ca51fef89624 FENNEC_45_0b9_RELEASE
-bf182675fd0584774210ca1cc092ca51fef89624 FENNEC_45_0b9_BUILD2
+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,40 +10,48 @@ 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
 
@@ -53,95 +61,142 @@ 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.
 
 ifndef TEST_MOZBUILD
-backend.RecursiveMakeBackend:
+
+.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
@@ -153,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
 
@@ -213,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
@@ -258,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*
@@ -645,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))
@@ -759,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());
@@ -1019,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);
@@ -1059,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();
@@ -1083,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);
 }
 
@@ -1660,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];
 }
 
@@ -1694,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/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.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
@@ -384,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,17 +47,26 @@ 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)
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -98,20 +107,33 @@ NotificationController::ScheduleChildDoc
   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
@@ -125,17 +147,17 @@ 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
@@ -173,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
@@ -191,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
@@ -385,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,18 +117,25 @@ 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);
@@ -235,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;
 
@@ -299,22 +272,22 @@ 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;
--- 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->IsRelocated()) {
-        *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/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
@@ -1100,19 +1100,16 @@ nsAccessibilityService::GetOrCreateAcces
         (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.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
@@ -1126,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))
@@ -1286,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()
@@ -1409,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/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) ||
@@ -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/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;
 
@@ -816,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
@@ -880,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()
 {
@@ -1006,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));
@@ -1987,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();
@@ -2004,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
 {
@@ -2129,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
@@ -2245,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);
@@ -2477,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); }
@@ -915,29 +925,40 @@ public:
   {
     if (aRelocated)
       mStateFlags |= eRelocated;
     else
       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);
@@ -1005,28 +1026,30 @@ protected:
     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
     eRelocated = 1 << 9, // accessible was moved in tree
+    eNoXBLKids = 1 << 10, // accessible don't allows XBL children
 
-    eLastStateFlag = eRelocated
+    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();
--- 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)
@@ -1414,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;
@@ -1480,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
@@ -1506,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;
@@ -1720,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;
@@ -1788,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)
@@ -1836,44 +1790,19 @@ 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);
     }
   }
 
   // Content insertion/removal is not cause of accessible tree change.
   if (updateFlags == eNoAccessible)
     return;
 
   MaybeNotifyOfValueChange(aContainer);
@@ -1887,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
@@ -1909,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.
@@ -1978,17 +1906,18 @@ DocAccessible::RelocateARIAOwnedIfNeeded
 void
 DocAccessible::ValidateARIAOwned()
 {
   for (auto it = mARIAOwnsHash.Iter(); !it.Done(); it.Next()) {
     Accessible* owner = it.Key();
     nsTArray<RefPtr<Accessible> >* children = it.UserData();
 
     // Owner is about to die, put children back if applicable.
-    if (!owner->IsInDocument()) {
+    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()) {
@@ -2053,19 +1982,23 @@ DocAccessible::DoARIAOwnsRelocation(Acce
       }
       // A referred child cannot be a parent of the owner.
       if (parent == child) {
         continue;
       }
     }
 
     if (child->Parent() == aOwner) {
-      MoveChild(child, insertIdx - 1);
+      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.
@@ -2082,32 +2015,42 @@ DocAccessible::SeizeChild(Accessible* aN
   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, aChild->GetContent(), false);
+  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()) {
@@ -2115,18 +2058,17 @@ DocAccessible::SeizeChild(Accessible* aN
     children->RemoveElement(aChild);
   }
 
   FireDelayedEvent(hideEvent);
   MaybeNotifyOfValueChange(oldParent);
   FireDelayedEvent(reorderEvent);
 
   reorderEvent = new AccReorderEvent(aNewParent);
-  RefPtr<AccMutationEvent> showEvent =
-    new AccShowEvent(aChild, aChild->GetContent());
+  RefPtr<AccMutationEvent> showEvent = new AccShowEvent(aChild);
   reorderEvent->AddSubMutationEvent(showEvent);
 
   FireDelayedEvent(showEvent);
   MaybeNotifyOfValueChange(aNewParent);
   FireDelayedEvent(reorderEvent);
 
   aChild->SetRelocated(true);
   return true;
@@ -2134,30 +2076,36 @@ DocAccessible::SeizeChild(Accessible* aN
 
 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, aChild->GetContent(), false);
+  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->RemoveChild(aChild);
+  parent->MoveChild(aIdxInParent, aChild);
+  aChild->SetRelocated(true);
 
-  parent->InsertChildAt(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, aChild->GetContent());
+  RefPtr<AccMutationEvent> showEvent = new AccShowEvent(aChild);
   reorderEvent->AddSubMutationEvent(showEvent);
   FireDelayedEvent(showEvent);
 
   MaybeNotifyOfValueChange(parent);
   FireDelayedEvent(reorderEvent);
 }
 
 void
@@ -2171,27 +2119,26 @@ DocAccessible::PutChildrenBack(nsTArray<
     // 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, child->GetContent(), false);
+      RefPtr<AccMutationEvent> hideEvent = new AccHideEvent(child, false);
       reorderEvent->AddSubMutationEvent(hideEvent);
+      FireDelayedEvent(hideEvent);
 
       {
         AutoTreeMutation mut(owner);
         owner->RemoveChild(child);
         child->SetRelocated(false);
       }
 
-      FireDelayedEvent(hideEvent);
       MaybeNotifyOfValueChange(owner);
       FireDelayedEvent(reorderEvent);
     }
 
     Accessible* container = GetContainerAccessible(child->GetContent());
     if (container &&
         containers.IndexOf(container) == nsTArray<Accessible*>::NoIndex) {
       containers.AppendElement(container);
--- 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
 
@@ -354,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);
@@ -376,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.
    */
--- 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();
@@ -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) {
--- 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.
@@ -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()
 {
 }
 
@@ -480,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
@@ -70,16 +70,42 @@ HTMLLabelAccessible::RelationByType(Rela
   if (aType == RelationType::LABEL_FOR) {
     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/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/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/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/ipc/DocAccessibleChild.cpp
+++ b/accessible/ipc/DocAccessibleChild.cpp
@@ -1043,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()));
     }
   }
 
@@ -1061,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()));
     }
   }
 
@@ -1363,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()));
     }
   }
 
@@ -1524,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/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,16 +234,29 @@ 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.
@@ -262,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
@@ -285,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:
@@ -154,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,38 +43,38 @@ 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);
@@ -127,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 {
@@ -767,17 +773,17 @@ ProxyAccessible::TableSelectedRowCount()
   uint32_t count = 0;
   Unused << mDoc->SendTableSelectedRowCount(mID, &count);
   return count;
 }
 
 void
 ProxyAccessible::TableSelectedCells(nsTArray<ProxyAccessible*>* aCellIDs)
 {
-  nsAutoTArray<uint64_t, 30> 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
@@ -846,17 +852,17 @@ ProxyAccessible::AtkTableRowHeader(int32
   bool ok = false;
   Unused << mDoc->SendAtkTableRowHeader(mID, aRow, &headerID, &ok);
   return ok ? mDoc->GetAccessible(headerID) : nullptr;
 }
 
 void
 ProxyAccessible::SelectedItems(nsTArray<ProxyAccessible*>* aSelectedItems)
 {
-  nsAutoTArray<uint64_t, 10> 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
--- 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,23 +63,32 @@ 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;
@@ -330,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':
--- 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;
@@ -613,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,18 +65,16 @@ 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;
@@ -156,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.
@@ -198,17 +201,16 @@ this.GestureTracker = { // jshint ignore
    * @param  {Number} aTimeStamp A new pointer event timeStamp.
    * @param  {Function} aGesture A gesture constructor (default: 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 || (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.
@@ -257,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.
@@ -358,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();
@@ -501,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
     };
@@ -525,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
@@ -593,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;
     }
   }
 };
@@ -665,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);
 }
@@ -691,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.
@@ -755,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/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/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;
           }
         }
       }
@@ -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/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
@@ -340,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) {
@@ -366,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.");
               }
             }
           }
         }
       }
     }
@@ -1663,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_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_valuechange.html
+++ b/accessible/tests/mochitest/events/test_valuechange.html
@@ -15,18 +15,16 @@
           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)
     {
@@ -127,16 +125,40 @@
       }
 
       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);
@@ -150,16 +172,19 @@
       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>
 
@@ -216,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/jsat/dom_helper.js
+++ b/accessible/tests/mochitest/jsat/dom_helper.js
@@ -2,19 +2,17 @@
 
 /* global getMainChromeWindow, AccessFuTest, GestureSettings, GestureTracker,
    SimpleTest, getBoundsForDOMElm, Point, Utils */
 /* exported loadJSON, eventMap */
 
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 
-Cu.import('resource://gre/modules/accessibility/Utils.jsm');
 Cu.import('resource://gre/modules/Geometry.jsm');
-Cu.import("resource://gre/modules/accessibility/Gestures.jsm");
 
 var win = getMainChromeWindow(window);
 
 /**
  * Convert inch based point coordinates into pixels.
  * @param  {Array} aPoints Array of coordinates in inches.
  * @return {Array} Array of coordinates in pixels.
  */
@@ -95,21 +93,16 @@ sendTouchEvent.touchList = null;
  * @type {Object}
  */
 var eventMap = {
   touchstart: sendTouchEvent,
   touchend: sendTouchEvent,
   touchmove: sendTouchEvent
 };
 
-var originalDwellThreshold = GestureSettings.dwellThreshold;
-var originalSwipeMaxDuration = GestureSettings.swipeMaxDuration;
-var originalConsecutiveGestureDelay =
-  GestureSettings.maxConsecutiveGestureDelay;
-
 /**
  * Attach a listener for the mozAccessFuGesture event that tests its
  * type.
  * @param  {Array} aExpectedGestures A stack of expected event types.
  * @param  {String} aTitle Title of this sequence, if any.
  * Note: the listener is removed once the stack reaches 0.
  */
 function testMozAccessFuGesture(aExpectedGestures, aTitle) {
@@ -153,19 +146,21 @@ function setTimers(aTimeStamp, aRemoveDw
   }
   if (aRemoveSwipeMaxDuration) {
     GestureSettings.swipeMaxDuration = 0;
   }
   GestureTracker.current.clearTimer();
   GestureTracker.current.startTimer(aTimeStamp);
 }
 
-function resetTimers() {
-  GestureSettings.dwellThreshold = originalDwellThreshold;
-  GestureSettings.swipeMaxDuration = originalSwipeMaxDuration;
+function resetTimers(aRemoveGestureResolveDelay) {
+  GestureSettings.dwellThreshold = AccessFuTest.dwellThreshold;
+  GestureSettings.swipeMaxDuration = AccessFuTest.swipeMaxDuration;
+  GestureSettings.maxGestureResolveTimeout = aRemoveGestureResolveDelay ?
+    0 : AccessFuTest.maxGestureResolveTimeout;
 }
 
 /**
  * An extention to AccessFuTest that adds an ability to test a sequence of
  * pointer events and their expected mozAccessFuGesture events.
  * @param {Object} aSequence An object that has a list of pointer events to be
  * generated and the expected mozAccessFuGesture events.
  */
@@ -174,20 +169,17 @@ AccessFuTest.addSequence = function Acce
     testMozAccessFuGesture(aSequence.expectedGestures, aSequence.title);
     var events = aSequence.events;
     function fireEvent(aEvent) {
       var event = {
         points: convertPointCoordinates(aEvent.points),
         type: aEvent.type
       };
       var timeStamp = Date.now();
-      resetTimers();
-      GestureSettings.maxConsecutiveGestureDelay =
-        aEvent.removeConsecutiveGestureDelay ?
-        0 : originalConsecutiveGestureDelay;
+      resetTimers(aEvent.removeGestureResolveDelay);
       GestureTracker.handle(event, timeStamp);
       setTimers(timeStamp, aEvent.removeDwellThreshold,
         aEvent.removeSwipeMaxDuration);
       processEvents();
     }
     function processEvents() {
       if (events.length === 0) {
         return;
--- a/accessible/tests/mochitest/jsat/gestures.json
+++ b/accessible/tests/mochitest/jsat/gestures.json
@@ -1,24 +1,24 @@
 [
   {
     "events": [
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}],
-       "removeConsecutiveGestureDelay": true }
+       "removeGestureResolveDelay": true }
     ],
     "expectedGestures": [{ "type": "tap" }]
   },
   {
     "events": [
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointermove",
         "points": [{"x": 1.03, "y": 1.03, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1.03, "y": 1.03, "identifier": 1}],
-       "removeConsecutiveGestureDelay": true }
+       "removeGestureResolveDelay": true }
     ],
     "expectedGestures": [{ "type": "tap" }]
   },
   {
     "events": [
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}],
         "removeDwellThreshold": true},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}
@@ -32,29 +32,29 @@
         "points": [{"x": 1.03, "y": 1.02, "identifier": 1}]},
       {"type": "pointerup",
         "points": [{"x": 1.03, "y": 1.02, "identifier": 1}]},
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointermove",
         "points": [{"x": 0.97, "y": 1.01, "identifier": 1}]},
       {"type": "pointerup",
         "points": [{"x": 0.97, "y": 1.01, "identifier": 1}],
-        "removeConsecutiveGestureDelay": true }
+        "removeGestureResolveDelay": true }
     ],
     "expectedGestures": [{ "type": "doubletap" }]
   },
   {
     "events": [
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}],
-       "removeConsecutiveGestureDelay": true }
+       "removeGestureResolveDelay": true }
     ],
     "expectedGestures": [{ "type": "tripletap" }]
   },
   {
     "events": [
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
@@ -287,17 +287,17 @@
       {"points": [
         {"y": 1.30098, "x": 1.52602, "identifier": 0},
         {"y": 1.94093, "x": 1.02672, "identifier": 1},
         {"y": 2.67229, "x": 0.75246, "identifier": 2}], "type": "pointerdown"},
       {"points": [
         {"y": 1.30098, "x": 1.52602, "identifier": 0},
         {"y": 1.94093, "x": 1.02672, "identifier": 1},
         {"y": 2.67229, "x": 0.75246, "identifier": 2}], "type": "pointerup",
-       "removeConsecutiveGestureDelay": false}],
+       "removeGestureResolveDelay": true}],
     "expectedGestures": [{ "type": "tripletap", "fingers": 3 }]
   },
   {
     "title": "Bug 1182311 - 3 finger triple tap is not reliable 2/2",
     "events": [
       {"type": "pointerdown",
        "points": [{"identifier": 0, "x": 2.21875, "y": 1.510417}]},
       {"type": "pointerdown",
@@ -338,21 +338,15 @@
        "points": [{"identifier": 2, "x": 2.15625, "y": 1.489583}]},
       {"type": "pointermove",
        "points": [{"identifier": 0, "x": 1.4375, "y": 2.59375},
                   {"identifier": 2, "x": 2.15625, "y": 1.489583}]},
       {"type": "pointermove",
        "points": [{"identifier": 0, "x": 1.4375, "y": 2.59375},
                   {"identifier": 2, "x": 2.15625, "y": 1.489583}]},
       {"type": "pointerup",
-       "points": [{"identifier": 1, "x": 1.083333, "y": 3.71875}]},
-      {"type": "pointermove",
-       "points": [{"identifier": 0, "x": 1.427083, "y": 2.59375}]},
-      {"type": "pointerup",
-       "points": [{"identifier": 0, "x": 1.427083, "y": 2.59375}]},
-      {"type": "pointerup",
-       "points": [{"identifier": 2, "x": 2.15625, "y": 1.489583}],
-       "removeConsecutiveGestureDelay": false}
+       "points": [{"identifier": 1, "x": 1.083333, "y": 3.71875}],
+       "removeGestureResolveDelay": true}
     ],
     "expectedGestures": [{ "type": "tripletap", "fingers": 3 }]
   }
 
 ]
--- a/accessible/tests/mochitest/jsat/jsatcommon.js
+++ b/accessible/tests/mochitest/jsat/jsatcommon.js
@@ -14,27 +14,16 @@ var gTestFuncs = [];
   */
 var gIterator;
 
 Components.utils.import('resource://gre/modules/Services.jsm');
 Components.utils.import("resource://gre/modules/accessibility/Utils.jsm");
 Components.utils.import("resource://gre/modules/accessibility/EventManager.jsm");
 Components.utils.import("resource://gre/modules/accessibility/Gestures.jsm");
 
-const dwellThreshold = GestureSettings.dwellThreshold;
-const swipeMaxDuration = GestureSettings.swipeMaxDuration;
-const maxConsecutiveGestureDelay = GestureSettings.maxConsecutiveGestureDelay;
-
-// https://bugzilla.mozilla.org/show_bug.cgi?id=1001945 - sometimes
-// SimpleTest.executeSoon timeout is bigger than the timer settings in
-// GestureSettings that causes intermittents.
-GestureSettings.dwellThreshold = dwellThreshold * 10;
-GestureSettings.swipeMaxDuration = swipeMaxDuration * 10;
-GestureSettings.maxConsecutiveGestureDelay = maxConsecutiveGestureDelay * 10;
-
 var AccessFuTest = {
 
   addFunc: function AccessFuTest_addFunc(aFunc) {
     if (aFunc) {
       gTestFuncs.push(aFunc);
     }
   },
 
@@ -106,19 +95,23 @@ var AccessFuTest = {
     this._waitForExplicitFinish = true;
   },
 
   finish: function AccessFuTest_finish() {
     // Disable the console service logging.
     Logger.test = false;
     Logger.logLevel = Logger.INFO;
     // Reset Gesture Settings.
-    GestureSettings.dwellThreshold = dwellThreshold;
-    GestureSettings.swipeMaxDuration = swipeMaxDuration;
-    GestureSettings.maxConsecutiveGestureDelay = maxConsecutiveGestureDelay;
+    GestureSettings.dwellThreshold = this.dwellThreshold =
+      this.originalDwellThreshold;
+    GestureSettings.swipeMaxDuration = this.swipeMaxDuration =
+      this.originalSwipeMaxDuration;
+    GestureSettings.maxGestureResolveTimeout =
+      this.maxGestureResolveTimeout =
+      this.originalMaxGestureResolveTimeout;
     // Finish through idle callback to let AccessFu._disable complete.
     SimpleTest.executeSoon(function () {
       AccessFu.detach();
       SimpleTest.finish();
     });
   },
 
   nextTest: function AccessFuTest_nextTest() {
@@ -155,16 +148,30 @@ var AccessFuTest = {
       Logger.test = true;
       Logger.logLevel = Logger.DEBUG;
     };
 
     var prefs = [['accessibility.accessfu.notify_output', 1],
       ['dom.mozSettings.enabled', true]];
     prefs.push.apply(prefs, aAdditionalPrefs);
 
+    this.originalDwellThreshold = GestureSettings.dwellThreshold;
+    this.originalSwipeMaxDuration = GestureSettings.swipeMaxDuration;
+    this.originalMaxGestureResolveTimeout =
+      GestureSettings.maxGestureResolveTimeout;
+    // https://bugzilla.mozilla.org/show_bug.cgi?id=1001945 - sometimes
+    // SimpleTest.executeSoon timeout is bigger than the timer settings in
+    // GestureSettings that causes intermittents.
+    this.dwellThreshold = GestureSettings.dwellThreshold =
+      GestureSettings.dwellThreshold * 10;
+    this.swipeMaxDuration = GestureSettings.swipeMaxDuration =
+      GestureSettings.swipeMaxDuration * 10;
+    this.maxGestureResolveTimeout = GestureSettings.maxGestureResolveTimeout =
+      GestureSettings.maxGestureResolveTimeout * 10;
+
     SpecialPowers.pushPrefEnv({ 'set': prefs }, function () {
       if (AccessFuTest._waitForExplicitFinish) {
         // Run all test functions asynchronously.
         AccessFuTest.nextTest();
       } else {
         // Run all test functions synchronously.
         gTestFuncs.forEach(testFunc => testFunc());
         AccessFuTest.finish();
--- a/accessible/tests/mochitest/jsat/test_live_regions.html
+++ b/accessible/tests/mochitest/jsat/test_live_regions.html
@@ -15,17 +15,17 @@
 
     function startAccessFu() {
       SpecialPowers.setIntPref("accessibility.accessfu.activate", 1);
       AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest);
     }
 
     function stopAccessFu() {
       SpecialPowers.setIntPref("accessibility.accessfu.activate", 0);
-      AccessFuTest.once_log("EventManager.stop", AccessFuTest.finish);
+      AccessFuTest.once_log("EventManager.stop", () => AccessFuTest.finish());
     }
 
     function hide(id) {
       var element = document.getElementById(id);
       element.style.display = "none";
     }
 
     function show(id) {
--- a/accessible/tests/mochitest/jsat/test_quicknav_modes.html
+++ b/accessible/tests/mochitest/jsat/test_quicknav_modes.html
@@ -63,17 +63,17 @@
           aCallback();
         });
       }
     }
 
     // Listen for initial 'EventManager.start' and disable AccessFu.
     function prefStop() {
       ok(AccessFu._enabled, "AccessFu was started via preference.");
-      AccessFuTest.once_log("EventManager.stop", AccessFuTest.finish);
+      AccessFuTest.once_log("EventManager.stop", () => AccessFuTest.finish());
       SpecialPowers.setIntPref("accessibility.accessfu.activate", 0);
     }
 
     function doTest() {
       AccessFuTest.addFunc(prefStart);
       AccessFuTest.addFunc(nextMode('Link', 'Heading'));
       AccessFuTest.addFunc(nextMode('Heading', 'FormElement'));
       AccessFuTest.addFunc(nextMode('FormElement', 'Link'));
--- a/accessible/tests/mochitest/name/a11y.ini
+++ b/accessible/tests/mochitest/name/a11y.ini
@@ -8,9 +8,10 @@ support-files =
 [test_browserui.xul]
 [test_counterstyle.html]
 [test_general.html]
 [test_general.xul]
 [test_link.html]
 [test_list.html]
 [test_markup.html]
 [test_svg.html]
+[test_toolbaritem.xul]
 [test_tree.xul]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/name/test_toolbaritem.xul
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<?xml-stylesheet href="general.css"
+                 type="text/css"?>
+
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="Accessibility Name Calculating Test.">
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../name.js"></script>
+  <script type="application/javascript">
+  <![CDATA[
+    var gQueue = null;
+    function doTest() {
+      let ids = [];
+      for (let item of ["button", "textbox"]) {
+        ids.push(item + "withtooltip");
+        ids.push(item + "withouttooltip");
+        ids.push("nested" + item + "withtooltip");
+        ids.push("nested" + item + "withouttooltip");
+      }
+
+      for (let id of ids) {
+        if (id.endsWith("withtooltip")) {
+          testName(id, id, id + " should have individual name from its tooltip - ");
+        } else {
+          testName(id, "Toolbaritem title", id + " should have toolbaritem's title for a name - ");
+        }
+      }
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  ]]>
+  </script>
+
+  <hbox flex="1" style="overflow: auto;">
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+    <a target="_blank"
+       href="https://bugzilla.mozilla.org/show_bug.cgi?id=1216478"
+       title="Items with tooltips inside items with a label should use their own tooltip as an accessible name, not the ancestor's label">
+      Mozilla Bug 1216478
+    </a>
+    <p id="display"></p>
+    <div id="content" style="display: none">
+    </div>
+    <pre id="test">
+    </pre>
+  </body>
+
+  <vbox flex="1">
+    <toolbox>
+      <toolbar>
+        <toolbaritem title="Toolbaritem title">
+          <toolbarbutton id="buttonwithtooltip" tooltiptext="buttonwithtooltip"/>
+          <toolbarbutton id="buttonwithouttooltip"/>
+          <textbox id="textboxwithtooltip" tooltiptext="textboxwithtooltip"/>
+          <textbox id="textboxwithouttooltip"/>
+          <vbox>
+            <toolbarbutton id="nestedbuttonwithtooltip" tooltiptext="nestedbuttonwithtooltip"/>
+            <toolbarbutton id="nestedbuttonwithouttooltip"/>
+            <textbox id="nestedtextboxwithtooltip" tooltiptext="nestedtextboxwithtooltip"/>
+            <textbox id="nestedtextboxwithouttooltip"/>
+          </vbox>
+        </toolbaritem>
+      </toolbar>
+    </toolbox>
+
+
+  </vbox> <!-- close tests area -->
+  </hbox> <!-- close main area -->
+</window>
--- a/accessible/tests/mochitest/relations/a11y.ini
+++ b/accessible/tests/mochitest/relations/a11y.ini
@@ -1,11 +1,10 @@
 [DEFAULT]
 
 [test_bindings.xhtml]
 [test_embeds.xul]
-skip-if = (os == "linux" && (debug || asan)) # Bug 845176
 [test_general.html]
 [test_general.xul]
 [test_tabbrowser.xul]
 [test_tree.xul]
 [test_ui_modalprompt.html]
 [test_update.html]
--- a/accessible/tests/mochitest/relations/test_embeds.xul
+++ b/accessible/tests/mochitest/relations/test_embeds.xul
@@ -32,61 +32,40 @@
     function loadURI(aURI)
     {
       this.invoke = function loadURI_invoke()
       {
         tabBrowser().loadURI(aURI);
       }
 
       this.eventSeq = [
-        new invokerChecker(EVENT_REORDER, currentBrowser)
+        new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, currentTabDocument)
       ];
 
       this.finalCheck = function loadURI_finalCheck()
       {
         testRelation(browserDocument(), RELATION_EMBEDS,
                      getAccessible(currentTabDocument()));
       }
 
       this.getID = function loadURI_getID()
       {
         return "load uri " + aURI;
       }
     }
 
-    function browserReorderChecker()
-    {
-      this.type = EVENT_REORDER;
-
-      this.match = function browserReorderChecker_match(aEvent)
-      {
-        if (!isAccessible(currentBrowser()))
-          return false;
-
-        // Reorder event might be duped because of temporary document creation.
-        if (aEvent.accessible == getAccessible(currentBrowser())) {
-          this.cnt++;
-          return this.cnt != 2;
-        }
-
-        return false;
-      }
-
-      this.cnt = 0;
-    }
-
     function loadOneTab(aURI)
     {
       this.invoke = function loadOneTab_invoke()
       {
         tabBrowser().loadOneTab(aURI, null, null, null, false);
       }
 
       this.eventSeq = [
-        new browserReorderChecker()
+        new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, currentTabDocument)
       ];
 
       this.finalCheck = function loadURI_finalCheck()
       {
         testRelation(browserDocument(), RELATION_EMBEDS,
                      getAccessible(currentTabDocument()));
       }
 
@@ -102,25 +81,25 @@
     //gA11yEventDumpToConsole = true; // debug
 
     var gQueue = null;
     function doTests()
     {
       testRelation(browserDocument(), RELATION_EMBEDS,
                    getAccessible(currentTabDocument()));
 
-      //enableLogging("docload");
+      enableLogging("docload");
       gQueue = new eventQueue();
 
       gQueue.push(new loadURI("about:about"));
       gQueue.push(new loadOneTab("about:mozilla"));
 
       gQueue.onFinish = function()
       {
-        //disableLogging();
+        disableLogging();
         closeBrowserWindow();
       }
       gQueue.invoke();
     }
 
     SimpleTest.waitForExplicitFinish();
     openBrowserWindow(doTests, "about:");
   ]]>
--- a/accessible/tests/mochitest/scroll/test_zoom.html
+++ b/accessible/tests/mochitest/scroll/test_zoom.html
@@ -27,17 +27,18 @@
 
       anchor.scrollToPoint(COORDTYPE_SCREEN_RELATIVE, docX, docY);
       testPos(anchor, [x, docY]);
 
       // scrollToPoint relative window
       anchor = getAccessible("bottom2");
       var [x, y] = getPos(anchor);
       var wnd = getRootAccessible().DOMDocument.defaultView;
-      var scrollToX = docX - wnd.screenX, scrollToY = docY - wnd.screenY;
+      var [screenX, screenY] = CSSToDevicePixels(wnd, wnd.screenX, wnd.screenY);
+      var scrollToX = docX - screenX, scrollToY = docY - screenY;
 
       anchor.scrollToPoint(COORDTYPE_WINDOW_RELATIVE, scrollToX, scrollToY);
       testPos(anchor, [x, docY]);
 
       // scrollToPoint relative parent
       anchor = getAccessible("bottom3");
       var [x, y] = getPos(anchor);
       var [parentX, parentY] = getPos(anchor.parent);
--- a/accessible/tests/mochitest/table/test_indexes_table.html
+++ b/accessible/tests/mochitest/table/test_indexes_table.html
@@ -105,17 +105,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       testTableIndexes("tableinsane4", idxes);
 
       //////////////////////////////////////////////////////////////////////////
       // tableinsane5 (just a crazy table)
       idxes = [
         [ 0,  1,  2, -1, -1],
         [-1, -1, -1, -1, -1],
         [ 3,  4,  5, -1, -1],
-        [ 6,  7,  7,  7,  7],
+        [ 6,  7,  -1,  -1,  -1],
         [ 6,  8,  9, -1, -1],
         [ 6, 10,  9, 11, 12]
       ];
       testTableIndexes("tableinsane5", idxes);
 
       //////////////////////////////////////////////////////////////////////////
       // tableinsane6 (overlapping cells, mad table)
       idxes = [
--- a/accessible/tests/mochitest/test_nsIAccessibleImage.html
+++ b/accessible/tests/mochitest/test_nsIAccessibleImage.html
@@ -11,16 +11,18 @@ https://bugzilla.mozilla.org/show_bug.cg
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <script type="application/javascript"
           src="common.js"></script>
   <script type="application/javascript"
           src="role.js"></script>
   <script type="application/javascript"
           src="attributes.js"></script>
+  <script type="application/javascript"
+          src="layout.js"></script>
 
   <script type="application/javascript">
     function testCoordinates(aID, aAcc, aWidth, aHeight)
     {
       var screenX = {}, screenY = {}, windowX = {}, windowY = {}, parentX = {},
           parentY = {};
 
       // get screen coordinates.
@@ -65,20 +67,21 @@ https://bugzilla.mozilla.org/show_bug.cg
         imageParentAcc.getBounds(parentAccX, parentAccY, parentAccWidth,
                                  parentAccHeight);
         is(parentAccX.value + parentX.value, screenX.value,
            "Wrong screen x coordinate for " + aID + "!");
 // XXX see bug 456344        is(parentAccY.value + parentY.value, screenY.value,
 //           "Wrong screen y coordinate for " + aID + "!");
       }
 
+      var [expected_w, expected_h] = CSSToDevicePixels(window, aWidth, aHeight);
       var width = {}, height = {};
       aAcc.getImageSize(width, height);
-      is(width.value, aWidth, "Wrong width for " + aID + "!");
-      is(height.value, aHeight, "wrong height for " + aID + "!");
+      is(width.value, expected_w, "Wrong width for " + aID + "!");
+      is(height.value, expected_h, "wrong height for " + aID + "!");
     }
 
     function testThis(aID, aSRC, aWidth, aHeight,
                       aActionCount, aActionNames)
     {
       var acc = getAccessible(aID, [nsIAccessibleImage]);
       if (!acc)
         return;
--- a/accessible/tests/mochitest/text.js
+++ b/accessible/tests/mochitest/text.js
@@ -468,16 +468,20 @@ function testTextRange(aRange, aRangeDes
            "Wrong start container of " + aRangeDescr);
   is(aRange.startOffset, aStartOffset,
      "Wrong start offset of " + aRangeDescr);
   isObject(aRange.endContainer, getAccessible(aEndContainer),
            "Wrong end container of " + aRangeDescr);
   is(aRange.endOffset, aEndOffset,
      "Wrong end offset of " + aRangeDescr);
 
+  if (aText === undefined) {
+    return;
+  }
+
   is(aRange.text, aText, "Wrong text of " + aRangeDescr);
 
   var children = aRange.embeddedChildren;
   is(children ? children.length : 0, aChildren ? aChildren.length : 0,
      "Wrong embedded children count of " + aRangeDescr);
 
   isObject(aRange.container, getAccessible(aCommonContainer),
            "Wrong container of " + aRangeDescr);
--- a/accessible/tests/mochitest/text/test_lineboundary.html
+++ b/accessible/tests/mochitest/text/test_lineboundary.html
@@ -231,25 +231,25 @@ two words
   <iframe id="ht_3" src="data:text/html,<div contentEditable='true'>foo<br/><br/></div>"></iframe>
 
   <p id="ht_4">Hello world
 </p>
 
   <ul id="ul1">
     <li id="li1">Item</li>
     <li id="li2"></li>
-    <li id="li3" style="width:10ex; font-family:monospace; font-size:10pt;">a long and winding road that lead me to your door</li>
+    <li id="li3" style="font-family:monospace; font-size:10pt; width:8ch;">a long and winding road that lead me to your door</li>
     <li id="li4">a <a href=''>b</a> c</li>
     <li id="li5"><br>hello</li>
   </ul>
 
   <ol id="ol1">
     <li id="li6">Item</li>
     <li id="li7"></li>
-    <li id="li8" style="width:10ex; font-family:monospace; font-size:10pt;">a long and winding road that lead me to your door</li>
+    <li id="li8" style="font-family:monospace; font-size:10pt; width:8ch;">a long and winding road that lead me to your door</li>
     <li id="li9">a <a href=''>b</a> c</li>
     <li id="li10"><br>hello</li>
   </ol>
 
   <div id="ht_5">
     <div>
       <p>sectiounus</p>
       <p>seciofarus</p>
--- a/accessible/tests/mochitest/textrange/a11y.ini
+++ b/accessible/tests/mochitest/textrange/a11y.ini
@@ -1,3 +1,4 @@
 [DEFAULT]
 
 [test_general.html]
+[test_selection.html]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/textrange/test_selection.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Text Range selection tests</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../text.js"></script>
+  <script type="application/javascript"
+          src="../layout.js"></script>
+  <script type="application/javascript">
+
+    function doTest()
+    {
+      var sel = window.getSelection();
+      var p = getNode("p1");
+      var a = getNode("p2_a");
+
+      var range = document.createRange();
+      sel.addRange(range);
+
+      // the accessible is contained by the range
+      range.selectNode(p);
+
+      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+
+      testTextRange(a11yrange, "selection range #1", document, 3, document, 4);
+
+      ok(a11yrange.crop(getAccessible(a)), "Range failed to crop #1.");
+      testTextRange(a11yrange, "cropped range #1", a, 0, a, 5);
+
+      // the range is contained by the accessible
+      range.selectNode(a);
+      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+
+      testTextRange(a11yrange, "selection range #2", p, 5, p, 6);
+
+      ok(a11yrange.crop(getAccessible(p)), "Range failed to crop #2.");
+      testTextRange(a11yrange, "cropped range #2", p, 5, p, 6);
+
+      // the range starts before the accessible and ends inside it
+      range.setStart(p, 0);
+      range.setEndAfter(a.firstChild, 4);
+      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+
+      testTextRange(a11yrange, "selection range #3", p, 0, a, 4);
+
+      ok(a11yrange.crop(getAccessible(a)), "Range failed to crop #3.");
+      testTextRange(a11yrange, "cropped range #3", a, 0, a, 4);
+
+      // the range starts inside the accessible and ends after it
+      range.setStart(a.firstChild, 1);
+      range.setEndAfter(p);
+      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+
+      testTextRange(a11yrange, "selection range #4", a, 1, document, 4);
+
+      ok(a11yrange.crop(getAccessible(a)), "Range failed to crop #4.");
+      testTextRange(a11yrange, "cropped range #4", a, 1, a, 5);
+
+      // the range ends before the accessible
+      range.setStart(p.firstChild, 0);
+      range.setEnd(p.firstChild, 4);
+      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+
+      testTextRange(a11yrange, "selection range #5", p, 0, p, 4);
+      ok(!a11yrange.crop(getAccessible(a)), "Crop #5 succeeded while it shouldn't");
+
+      // the range starts after the accessible
+      range.setStart(p.lastChild, 0);
+      range.setEnd(p.lastChild, 4);
+      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+
+      testTextRange(a11yrange, "selection range #6", p, 6, p, 10);
+
+      ok(!a11yrange.crop(getAccessible(a)), "Crop #6 succeeded while it shouldn't");
+
+      // crop a range by a table
+      range.selectNode(getNode("c2"));
+      var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
+      var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
+
+      testTextRange(a11yrange, "selection range #7", document, 4, document, 5);
+
+      ok(a11yrange.crop(getAccessible("table")), "Range failed to crop #7.");
+      testTextRange(a11yrange, "cropped range #7", "c2", 5, "c2", 6);
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     title="Implement IAccessible2_3::selectionRanges"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=1233118">Bug 1233118</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <p id="p1">text <a id="p2_a" href="www">link<img id="p2_img", src="../moz.png"></a> text</p>
+
+  <div id="c2">start<table id="table"><tr><td>cell</td></tr></table>end</div>
+</body>
+</html>
--- a/accessible/tests/mochitest/treeupdate/a11y.ini
+++ b/accessible/tests/mochitest/treeupdate/a11y.ini
@@ -24,11 +24,12 @@ skip-if = buildapp == "mulet"
 [test_list_editabledoc.html]
 [test_listbox.xul]
 [test_menu.xul]
 [test_menubutton.xul]
 [test_optgroup.html]
 [test_recreation.html]
 [test_select.html]
 [test_shutdown.xul]
+[test_table.html]
 [test_textleaf.html]
 [test_visibility.html]
 [test_whitespace.html]
--- a/accessible/tests/mochitest/treeupdate/test_ariaowns.html
+++ b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
@@ -18,38 +18,75 @@
           src="../events.js"></script>
 
   <script type="application/javascript">
 
     ////////////////////////////////////////////////////////////////////////////
     // Invokers
     ////////////////////////////////////////////////////////////////////////////
 
-    function removeARIAOwns()
+    function changeARIAOwns()
     {
       this.eventSeq = [
-        new invokerChecker(EVENT_HIDE, getNode("t1_checkbox")),
         new invokerChecker(EVENT_HIDE, getNode("t1_button")),
         new invokerChecker(EVENT_SHOW, getNode("t1_button")),
+        new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")),
+        new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
+        new invokerChecker(EVENT_HIDE, getNode("t1_checkbox")),
         new invokerChecker(EVENT_SHOW, getNode("t1_checkbox")),
         new invokerChecker(EVENT_REORDER, getNode("t1_container"))
       ];
 
-      this.invoke = function removeARIAOwns_invoke()
+      this.invoke = function setARIAOwns_invoke()
       {
-        // children are swapped
+        // children are swapped by ARIA owns
         var tree =
           { SECTION: [
               { CHECKBUTTON: [
                 { SECTION: [] }
               ] },
               { PUSHBUTTON: [ ] }
           ] };
         testAccessibleTree("t1_container", tree);
 
+        getNode("t1_container").
+          setAttribute("aria-owns", "t1_button t1_subdiv");
+      }
+
+      this.finalCheck = function setARIAOwns_finalCheck()
+      {
+        // children are swapped again, button and subdiv are appended to
+        // the children.
+        var tree =
+          { SECTION: [
+              { CHECKBUTTON: [ ] }, // checkbox, native order
+              { PUSHBUTTON: [ ] }, // button, rearranged by ARIA own
+              { SECTION: [ ] } // subdiv from the subtree, ARIA owned
+          ] };
+        testAccessibleTree("t1_container", tree);
+      }
+
+      this.getID = function setARIAOwns_getID()
+      {
+        return "Change @aria-owns attribute";
+      }
+    }
+
+    function removeARIAOwns()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, getNode("t1_button")),
+        new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")),
+        new invokerChecker(EVENT_SHOW, getNode("t1_button")),
+        new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
+        new invokerChecker(EVENT_REORDER, getNode("t1_container"))
+      ];
+
+      this.invoke = function removeARIAOwns_invoke()
+      {
         getNode("t1_container").removeAttribute("aria-owns");
       }
 
       this.finalCheck = function removeARIAOwns_finalCheck()
       {
         // children follow the DOM order
         var tree =
           { SECTION: [
@@ -399,30 +436,100 @@
       }
 
       this.getID = function showHiddenElement_getID()
       {
         return "Show hidden ARIA owns referred element";
       }
     }
 
+    function rearrangeARIAOwns(aContainer, aAttr, aIdList, aRoleList)
+    {
+      this.eventSeq = [];
+      for (var id of aIdList) {
+        this.eventSeq.push(new invokerChecker(EVENT_HIDE, getNode(id)));
+        this.eventSeq.push(new invokerChecker(EVENT_SHOW, getNode(id)));
+      }
+      this.eventSeq.push(new invokerChecker(EVENT_REORDER, getNode(aContainer)));
+
+      this.invoke = function rearrangeARIAOwns_invoke()
+      {
+        getNode(aContainer).setAttribute("aria-owns", aAttr);
+      }
+
+      this.finalCheck = function rearrangeARIAOwns_finalCheck()
+      {
+        var tree = { SECTION: [ ] };
+        for (var role of aRoleList) {
+          var ch = {};
+          ch[role] = [];
+          tree["SECTION"].push(ch);
+        }
+        testAccessibleTree(aContainer, tree);
+      }
+
+      this.getID = function rearrangeARIAOwns_getID()
+      {
+        return `Rearrange @aria-owns attribute to '${aAttr}'`;
+      }
+    }
+
+    function removeNotARIAOwnedEl(aContainer, aChild)
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_REORDER, aContainer)
+      ];
+
+      this.invoke = function removeNotARIAOwnedEl_invoke()
+      {
+        dumpTree(aContainer, "before");
+        var tree = {
+          SECTION: [
+            { TEXT_LEAF: [ ] },
+            { GROUPING: [ ] }
+          ]
+        };
+        testAccessibleTree(aContainer, tree);
+
+        getNode(aContainer).removeChild(getNode(aChild));
+      }
+
+      this.finalCheck = function removeNotARIAOwnedEl_finalCheck()
+      {
+        dumpTree(aContainer, "after");
+        var tree = {
+          SECTION: [
+            { GROUPING: [ ] }
+          ]
+        };
+        testAccessibleTree(aContainer, tree);
+      }
+
+      this.getID = function removeNotARIAOwnedEl_getID()
+      {
+        return `remove not ARIA owned child`;
+      }
+    }
+
+
     ////////////////////////////////////////////////////////////////////////////
     // Test
     ////////////////////////////////////////////////////////////////////////////
 
     //gA11yEventDumpToConsole = true;
-    //enableLogging("tree"); // debug stuff
+    //enableLogging("tree,verbose"); // debug stuff
 
     var gQueue = null;
 
     function doTest()
     {
       gQueue = new eventQueue();
 
       // test1
+      gQueue.push(new changeARIAOwns());
       gQueue.push(new removeARIAOwns());
       gQueue.push(new setARIAOwns());
       gQueue.push(new addIdToARIAOwns());
       gQueue.push(new appendEl());
       gQueue.push(new removeEl());
       gQueue.push(new removeId());
       gQueue.push(new setId());
 
@@ -431,16 +538,28 @@
 
       // test3
       gQueue.push(new stealFromOtherARIAOwns());
       gQueue.push(new appendElToRecacheChildren());
 
       // test4
       gQueue.push(new showHiddenElement());
 
+      // test5
+      gQueue.push(new rearrangeARIAOwns(
+        "t5_container", "t5_checkbox t5_radio t5_button",
+        [ "t5_checkbox", "t5_radio", "t5_button" ],
+        [ "CHECKBUTTON", "RADIOBUTTON", "PUSHBUTTON" ]));
+      gQueue.push(new rearrangeARIAOwns(
+        "t5_container", "t5_radio t5_button t5_checkbox",
+        [ "t5_radio", "t5_button" ],
+        [ "RADIOBUTTON", "PUSHBUTTON", "CHECKBUTTON" ]));
+
+      gQueue.push(new removeNotARIAOwnedEl("t6_container", "t6_span"));
+
       gQueue.invoke(); // SimpleTest.finish() will be called in the end
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
 
   </script>
 </head>
@@ -472,11 +591,22 @@
   <div id="t3_child" role="checkbox"></div>
   <div id="t3_container2"></div>
 
   <div id="t4_container1" aria-owns="t4_child1 t4_child2"></div>
   <div id="t4_container2">
     <div id="t4_child1" style="display:none" role="checkbox"></div>
     <div id="t4_child2" role="radio"></div>
   </div>
+
+  <div id="t5_container">
+    <div role="button" id="t5_button"></div>
+    <div role="checkbox" id="t5_checkbox"></div>
+    <div role="radio" id="t5_radio"></div>
+  </div>
+
+  <div id="t6_container" aria-owns="t6_fake">
+    <span id="t6_span">hey</span>
+  </div>
+  <div id="t6_fake" role="group"></div>
 </body>
 
 </html>
--- a/accessible/tests/mochitest/treeupdate/test_optgroup.html
+++ b/accessible/tests/mochitest/treeupdate/test_optgroup.html
@@ -97,17 +97,17 @@
       }
 
       this.getID = function removeOptGroup_getID()
       {
         return "test optgroup's removal from a select";
       }
     }
 
-//    gA11yEventDumpToConsole = true;
+    //gA11yEventDumpToConsole = true;
 
     function doTest()
     {
       gQueue = new eventQueue();
 
       gQueue.push(new addOptGroup("select"));
       gQueue.push(new removeOptGroup("select"));
 
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_table.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Table update tests</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+
+    function appendCaption(aTableID)
+    {
+      this.invoke = function appendCaption_invoke()
+      {
+        // append a caption, it should appear as a first element in the
+        // accessible tree.
+        var caption = document.createElement("caption");
+        caption.textContent = "table caption";
+        getNode(aTableID).appendChild(caption);
+      }
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_REORDER, aTableID)
+      ];
+
+      this.finalCheck = function appendCaption_finalCheck()
+      {
+        var tree =
+          { TABLE: [
+            { CAPTION: [ 
+              { TEXT_LEAF: [] }
+            ] },
+            { ROW: [ 
+              { CELL: [ {TEXT_LEAF: [] }]},
+              { CELL: [ {TEXT_LEAF: [] }]}
+            ] }
+          ] };
+        testAccessibleTree(aTableID, tree);
+      }
+
+      this.getID = function appendCaption_getID()
+      {
+        return "append caption";
+      }
+    }
+
+    function doTest()
+    {
+      gQueue = new eventQueue();
+      gQueue.push(new appendCaption("table"));
+      gQueue.invoke(); // Will call SimpleTest.finish();
+
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <table id="table">
+    <tr>
+      <td>cell1</td>
+      <td>cell2</td>
+    </tr>
+  </table>
+</body>
+</html>
--- a/accessible/windows/ia2/ia2Accessible.cpp
+++ b/accessible/windows/ia2/ia2Accessible.cpp
@@ -3,26 +3,28 @@
 /* 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 "AccessibleWrap.h"
 
 #include "Accessible2_i.c"
 #include "Accessible2_2_i.c"
+#include "Accessible2_3_i.c"
 #include "AccessibleRole.h"
 #include "AccessibleStates.h"
 
 #include "Compatibility.h"
 #include "ia2AccessibleRelation.h"
 #include "IUnknownImpl.h"
 #include "nsCoreUtils.h"
 #include "nsIAccessibleTypes.h"
 #include "mozilla/a11y/PDocAccessible.h"
 #include "Relation.h"
+#include "TextRange-inl.h"
 #include "nsAccessibilityService.h"
 
 #include "nsIPersistentProperties2.h"
 #include "nsISimpleEnumerator.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
@@ -35,17 +37,19 @@ template<typename String> static void Es
 STDMETHODIMP
 ia2Accessible::QueryInterface(REFIID iid, void** ppv)
 {
   if (!ppv)
     return E_INVALIDARG;
 
   *ppv = nullptr;
 
-  if (IID_IAccessible2_2 == iid)
+  if (IID_IAccessible2_3 == iid)
+    *ppv = static_cast<IAccessible2_3*>(this);
+  else if (IID_IAccessible2_2 == iid)
     *ppv = static_cast<IAccessible2_2*>(this);
   else if (IID_IAccessible2 == iid && !Compatibility::IsIA2Off())
     *ppv = static_cast<IAccessible2*>(this);
 
   if (*ppv) {
     (reinterpret_cast<IUnknown*>(*ppv))->AddRef();
     return S_OK;
   }
@@ -242,17 +246,17 @@ ia2Accessible::role(long* aRole)
   if (acc->IsProxy())
     geckoRole = acc->Proxy()->Role();
   else
     geckoRole = acc->Role();
   switch (geckoRole) {
 #include "RoleMap.h"
     default:
       MOZ_CRASH("Unknown role.");
-  };
+  }
 
 #undef ROLE
 
   // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call
   // the IA2 role a ROLE_OUTLINEITEM.
   if (acc->IsProxy()) {
     if (geckoRole == roles::ROW && acc->Proxy()->Parent() &&
         acc->Proxy()->Parent()->Role() == roles::TREE_TABLE)
@@ -744,16 +748,68 @@ ia2Accessible::get_relationTargetsOfType
     (*aTargets)[i]->AddRef();
   }
 
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
+STDMETHODIMP
+ia2Accessible::get_selectionRanges(IA2Range** aRanges,
+                                   long *aNRanges)
+{
+  A11Y_TRYBLOCK_BEGIN
+
+  if (!aRanges || !aNRanges || aNRanges <= 0)
+    return E_INVALIDARG;
+
+  *aNRanges = 0;
+
+  AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
+  if (acc->IsDefunct())
+    return CO_E_OBJNOTCONNECTED;
+
+  AutoTArray<TextRange, 1> ranges;
+  acc->Document()->SelectionRanges(&ranges);
+  uint32_t len = ranges.Length();
+  for (uint32_t idx = 0; idx < len; idx++) {
+    if (!ranges[idx].Crop(acc)) {
+      ranges.RemoveElementAt(idx);
+    }
+  }
+
+  *aNRanges = ranges.Length();
+  *aRanges = static_cast<IA2Range*>(
+    ::CoTaskMemAlloc(sizeof(IA2Range) * *aNRanges));
+  if (!*aRanges)
+    return E_OUTOFMEMORY;
+
+  for (uint32_t idx = 0; idx < static_cast<uint32_t>(*aNRanges); idx++) {
+    AccessibleWrap* anchor =
+      static_cast<AccessibleWrap*>(ranges[idx].StartContainer());
+    (*aRanges)[idx].anchor = static_cast<IAccessible2*>(anchor);
+    anchor->AddRef();
+
+    (*aRanges)[idx].anchorOffset = ranges[idx].StartOffset();
+
+    AccessibleWrap* active =
+      static_cast<AccessibleWrap*>(ranges[idx].EndContainer());
+    (*aRanges)[idx].active = static_cast<IAccessible2*>(active);
+    active->AddRef();
+
+    (*aRanges)[idx].activeOffset = ranges[idx].EndOffset();
+  }
+
+  return S_OK;
+
+  A11Y_TRYBLOCK_END
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////
 // Helpers
 
 template<typename String>
 static inline void
 EscapeAttributeChars(String& aStr)
 {
   int32_t offset = 0;
--- a/accessible/windows/ia2/ia2Accessible.h
+++ b/accessible/windows/ia2/ia2Accessible.h
@@ -4,23 +4,23 @@
  * 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_ia2Accessible_h_
 #define mozilla_a11y_ia2Accessible_h_
 
 #include "nsISupports.h"
 
-#include "Accessible2_2.h"
+#include "Accessible2_3.h"
 
 namespace mozilla {
 namespace a11y {
 class Attribute;
 
-class ia2Accessible : public IAccessible2_2
+class ia2Accessible : public IAccessible2_3
 {
 public:
 
   // IUnknown
   STDMETHODIMP QueryInterface(REFIID, void**);
 
   // IAccessible2
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_nRelations(
@@ -99,16 +99,21 @@ public:
 
   virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_relationTargetsOfType(
     /* [in] */ BSTR type,
     /* [in] */ long maxTargets,
     /* [out, size_is(,*nTargets)] */ IUnknown*** targets,
     /* [out, retval] */ long* nTargets
   );
 
+  // IAccessible2_3
+  virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectionRanges(
+    /* [out, size_is(,*nRanges)] */ IA2Range** ranges,
+    /* [out, retval] */ long *nRanges);
+
   // Helper method
   static HRESULT ConvertToIA2Attributes(nsIPersistentProperties* aAttributes,
                                         BSTR* aIA2Attributes);
   static HRESULT ConvertToIA2Attributes(nsTArray<Attribute>* aAttributes,
                                         BSTR* aIA2Attributes);
 };
 
 } // namespace a11y
--- a/accessible/windows/ia2/ia2AccessibleTable.cpp
+++ b/accessible/windows/ia2/ia2AccessibleTable.cpp
@@ -366,17 +366,17 @@ ia2AccessibleTable::get_selectedChildren
   if (!aChildren || !aNChildren)
     return E_INVALIDARG;
 
   *aChildren = nullptr;
   *aNChildren = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
-  nsAutoTArray<uint32_t, 30> cellIndices;
+  AutoTArray<uint32_t, 30> cellIndices;
   mTable->SelectedCellIndices(&cellIndices);
 
   uint32_t maxCells = cellIndices.Length();
   if (maxCells == 0)
     return S_FALSE;
 
   *aChildren = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxCells));
   *aNChildren = maxCells;
@@ -658,17 +658,17 @@ ia2AccessibleTable::get_selectedCells(IU
   if (!aCells || !aNSelectedCells)
     return E_INVALIDARG;
 
   *aCells = nullptr;
   *aNSelectedCells = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
-  nsAutoTArray<Accessible*, 30> cells;
+  AutoTArray<Accessible*, 30> cells;
   mTable->SelectedCells(&cells);
   if (cells.IsEmpty())
     return S_FALSE;
 
   *aCells =
     static_cast<IUnknown**>(::CoTaskMemAlloc(sizeof(IUnknown*) *
                                              cells.Length()));
   if (!*aCells)
@@ -694,17 +694,17 @@ ia2AccessibleTable::get_selectedColumns(
   if (!aColumns || !aNColumns)
     return E_INVALIDARG;
 
   *aColumns = nullptr;
   *aNColumns = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
-  nsAutoTArray<uint32_t, 30> colIndices;
+  AutoTArray<uint32_t, 30> colIndices;
   mTable->SelectedColIndices(&colIndices);
 
   uint32_t maxCols = colIndices.Length();
   if (maxCols == 0)
     return S_FALSE;
 
   *aColumns = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxCols));
   *aNColumns = maxCols;
@@ -724,17 +724,17 @@ ia2AccessibleTable::get_selectedRows(lon
   if (!aRows || !aNRows)
     return E_INVALIDARG;
 
   *aRows = nullptr;
   *aNRows = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
-  nsAutoTArray<uint32_t, 30> rowIndices;
+  AutoTArray<uint32_t, 30> rowIndices;
   mTable->SelectedRowIndices(&rowIndices);
 
   uint32_t maxRows = rowIndices.Length();
   if (maxRows == 0)
     return S_FALSE;
 
   *aRows = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxRows));
   *aNRows = maxRows;
--- a/accessible/windows/ia2/ia2AccessibleTableCell.cpp
+++ b/accessible/windows/ia2/ia2AccessibleTableCell.cpp
@@ -95,17 +95,17 @@ ia2AccessibleTableCell::get_columnHeader
   if (!aCellAccessibles || !aNColumnHeaderCells)
     return E_INVALIDARG;
 
   *aCellAccessibles = nullptr;
   *aNColumnHeaderCells = 0;
   if (!mTableCell)
     return CO_E_OBJNOTCONNECTED;
 
-  nsAutoTArray<Accessible*, 10> cells;
+  AutoTArray<Accessible*, 10> cells;
   mTableCell->ColHeaderCells(&cells);
 
   *aNColumnHeaderCells = cells.Length();
   *aCellAccessibles =
     static_cast<IUnknown**>(::CoTaskMemAlloc(sizeof(IUnknown*) *
                                              cells.Length()));
 
   if (!*aCellAccessibles)
@@ -167,17 +167,17 @@ ia2AccessibleTableCell::get_rowHeaderCel
   if (!aCellAccessibles || !aNRowHeaderCells)
     return E_INVALIDARG;
 
   *aCellAccessibles = nullptr;
   *aNRowHeaderCells = 0;
   if (!mTableCell)
     return CO_E_OBJNOTCONNECTED;
 
-  nsAutoTArray<Accessible*, 10> cells;
+  AutoTArray<Accessible*, 10> cells;
   mTableCell->RowHeaderCells(&cells);
 
   *aNRowHeaderCells = cells.Length();
   *aCellAccessibles =
     static_cast<IUnknown**>(::CoTaskMemAlloc(sizeof(IUnknown*) *
                                              cells.Length()));
   if (!*aCellAccessibles)
     return E_OUTOFMEMORY;
--- a/accessible/windows/ia2/ia2AccessibleText.cpp
+++ b/accessible/windows/ia2/ia2AccessibleText.cpp
@@ -56,17 +56,17 @@ ia2AccessibleText::get_attributes(long a
 
   *aStartOffset = 0;
   *aEndOffset = 0;
   *aTextAttributes = nullptr;
 
   int32_t startOffset = 0, endOffset = 0;
   HRESULT hr;
   if (ProxyAccessible* proxy = HyperTextProxyFor(this)) {
-    nsAutoTArray<Attribute, 10> attrs;
+    AutoTArray<Attribute, 10> attrs;
     proxy->TextAttributes(true, aOffset, &attrs, &startOffset, &endOffset);
     hr = AccessibleWrap::ConvertToIA2Attributes(&attrs, aTextAttributes);
   } else {
     HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
     if (textAcc->IsDefunct())
       return CO_E_OBJNOTCONNECTED;
 
     nsCOMPtr<nsIPersistentProperties> attributes =
--- a/accessible/windows/ia2/moz.build
+++ b/accessible/windows/ia2/moz.build
@@ -45,9 +45,17 @@ LOCAL_INCLUDES += [
     '/accessible/xul',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wshadow']
 
+# 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']
+
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/accessible/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/windows/msaa/AccessibleWrap.cpp
@@ -86,18 +86,23 @@ AccessibleWrap::~AccessibleWrap()
 ITypeInfo* AccessibleWrap::gTypeInfo = nullptr;
 
 NS_IMPL_ISUPPORTS_INHERITED0(AccessibleWrap, Accessible)
 
 void
 AccessibleWrap::Shutdown()
 {
 #ifdef _WIN64
-  if (mID != kNoID)
-    static_cast<DocAccessibleWrap*>(mDoc)->RemoveID(mID);
+  if (mID != kNoID) {
+    auto doc = static_cast<DocAccessibleWrap*>(mDoc);
+    MOZ_ASSERT(doc);
+    if (doc) {
+      doc->RemoveID(mID);
+    }
+  }
 #endif
 
   Accessible::Shutdown();
 }
 
 //-----------------------------------------------------
 // IUnknown interface methods - see iunknown.h for documentation
 //-----------------------------------------------------
@@ -442,17 +447,17 @@ AccessibleWrap::get_accRole(
   case roles::_geckoRole: \
     msaaRole = _msaaRole; \
     break;
 
   switch (geckoRole) {
 #include "RoleMap.h"
     default:
       MOZ_CRASH("Unknown role.");
-  };
+  }
 
 #undef ROLE
 
   // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call the MSAA role
   // a ROLE_OUTLINEITEM for consistency and compatibility.
   // We need this because ARIA has a role of "row" for both grid and treegrid
   if (xpAccessible->IsProxy()) {
       if (geckoRole == roles::ROW
@@ -824,17 +829,17 @@ AccessibleWrap::get_accSelection(VARIANT
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   // TODO make this work with proxies.
   if (IsProxy())
     return E_NOTIMPL;
 
   if (IsSelect()) {
-    nsAutoTArray<Accessible*, 10> selectedItems;
+    AutoTArray<Accessible*, 10> selectedItems;
     if (IsProxy()) {
       nsTArray<ProxyAccessible*> proxies;
       Proxy()->SelectedItems(&proxies);
 
       uint32_t selectedCount = proxies.Length();
       for (uint32_t i = 0; i < selectedCount; i++) {
         selectedItems.AppendElement(WrapperFor(proxies[i]));
       }
--- a/accessible/windows/msaa/DocAccessibleWrap.cpp
+++ b/accessible/windows/msaa/DocAccessibleWrap.cpp
@@ -20,19 +20,18 @@
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocAccessibleWrap
 ////////////////////////////////////////////////////////////////////////////////
 
 DocAccessibleWrap::
-  DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                    nsIPresShell* aPresShell) :
-  DocAccessible(aDocument, aRootContent, aPresShell), mHWND(nullptr)
+  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  DocAccessible(aDocument, aPresShell), mHWND(nullptr)
 {
 }
 
 DocAccessibleWrap::~DocAccessibleWrap()
 {
 }
 
 IMPL_IUNKNOWN_QUERY_HEAD(DocAccessibleWrap)
--- a/accessible/windows/msaa/DocAccessibleWrap.h
+++ b/accessible/windows/msaa/DocAccessibleWrap.h
@@ -10,18 +10,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();
 
   DECL_IUNKNOWN_INHERITED
 
   // IAccessible
 
     // Override get_accValue to provide URL when no other value is available
     virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue( 
--- a/accessible/windows/msaa/RootAccessibleWrap.cpp
+++ b/accessible/windows/msaa/RootAccessibleWrap.cpp
@@ -10,19 +10,18 @@
 #include "nsWinUtils.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor/desctructor
 
 RootAccessibleWrap::
-  RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                     nsIPresShell* aPresShell) :
-  RootAccessible(aDocument, aRootContent, aPresShell)
+  RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  RootAccessible(aDocument, aPresShell)
 {
 }
 
 RootAccessibleWrap::~RootAccessibleWrap()
 {
 }
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/windows/msaa/RootAccessibleWrap.h
+++ b/accessible/windows/msaa/RootAccessibleWrap.h
@@ -9,18 +9,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();
 
   // RootAccessible
   virtual void DocumentActivated(DocAccessible* aDocument);
 };
 
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/windows/msaa/moz.build
+++ b/accessible/windows/msaa/moz.build
@@ -54,14 +54,22 @@ LOCAL_INCLUDES += [
     '/accessible/windows/sdn',
     '/accessible/windows/uia',
     '/accessible/xpcom',
     '/accessible/xul',
     '/dom/base',
     '/layout/style',
 ]
 
+# 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']
+
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wshadow']
--- a/accessible/windows/msaa/nsWinUtils.cpp
+++ b/accessible/windows/msaa/nsWinUtils.cpp
@@ -40,18 +40,17 @@ nsRefPtrHashtable<nsPtrHashKey<void>, Do
 already_AddRefed<nsIDOMCSSStyleDeclaration>
 nsWinUtils::GetComputedStyleDeclaration(nsIContent* aContent)
 {
   nsIContent* elm = nsCoreUtils::GetDOMElementFor(aContent);
   if (!elm)
     return nullptr;
 
   // Returns number of items in style declaration
-  nsCOMPtr<nsPIDOMWindow> window =
-    do_QueryInterface(elm->OwnerDoc()->GetInnerWindow());
+  nsCOMPtr<nsPIDOMWindowInner> window = elm->OwnerDoc()->GetInnerWindow();
   if (!window)
     return nullptr;
 
   ErrorResult dummy;
   nsCOMPtr<nsICSSDeclaration> cssDecl;
   nsCOMPtr<Element> domElement(do_QueryInterface(elm));
   cssDecl = window->GetComputedStyle(*domElement, EmptyString(), dummy);
   nsCOMPtr<nsIDOMCSSStyleDeclaration> domDecl = do_QueryInterface(cssDecl);
--- a/accessible/xpcom/moz.build
+++ b/accessible/xpcom/moz.build
@@ -59,8 +59,10 @@ xpc_acc_events_h = GENERATED_FILES['xpcA
 xpc_acc_events_h.script = 'AccEventGen.py:gen_header_file'
 xpc_acc_events_h.inputs += ['AccEvents.conf']
 
 xpc_acc_events_cpp = GENERATED_FILES['xpcAccEvents.cpp']
 xpc_acc_events_cpp.script = 'AccEventGen.py:gen_cpp_file'
 xpc_acc_events_cpp.inputs += ['AccEvents.conf']
 
 FINAL_LIBRARY = 'xul'
+
+include('/ipc/chromium/chromium-config.mozbuild')
--- a/accessible/xpcom/xpcAccessible.cpp
+++ b/accessible/xpcom/xpcAccessible.cpp
@@ -1,15 +1,16 @@
 /* -*- 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 "Accessible-inl.h"
+#include "mozilla/a11y/DocAccessibleParent.h"
 #include "nsAccUtils.h"
 #include "nsIAccessibleRelation.h"
 #include "nsIAccessibleRole.h"
 #include "nsAccessibleRelation.h"
 #include "Relation.h"
 #include "Role.h"
 #include "RootAccessible.h"
 #include "xpcAccessibleDocument.h"
@@ -60,91 +61,91 @@ xpcAccessible::GetPreviousSibling(nsIAcc
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetFirstChild(nsIAccessible** aFirstChild)
 {
   NS_ENSURE_ARG_POINTER(aFirstChild);
   *aFirstChild = nullptr;
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
-  NS_IF_ADDREF(*aFirstChild = ToXPC(Intl()->FirstChild()));
+  NS_IF_ADDREF(*aFirstChild = ToXPC(IntlGeneric().FirstChild()));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetLastChild(nsIAccessible** aLastChild)
 {
   NS_ENSURE_ARG_POINTER(aLastChild);
   *aLastChild = nullptr;
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
-  NS_IF_ADDREF(*aLastChild = ToXPC(Intl()->LastChild()));
+  NS_IF_ADDREF(*aLastChild = ToXPC(IntlGeneric().LastChild()));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetChildCount(int32_t* aChildCount)
 {
   NS_ENSURE_ARG_POINTER(aChildCount);
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
-  *aChildCount = Intl()->ChildCount();
+  *aChildCount = IntlGeneric().ChildCount();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetChildAt(int32_t aChildIndex, nsIAccessible** aChild)
 {
   NS_ENSURE_ARG_POINTER(aChild);
   *aChild = nullptr;
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
   // If child index is negative, then return last child.
   // XXX: do we really need this?
   if (aChildIndex < 0)
-    aChildIndex = Intl()->ChildCount() - 1;
+    aChildIndex = IntlGeneric().ChildCount() - 1;
 
-  Accessible* child = Intl()->GetChildAt(aChildIndex);
-  if (!child)
+  AccessibleOrProxy child = IntlGeneric().ChildAt(aChildIndex);
+  if (child.IsNull())
     return NS_ERROR_INVALID_ARG;
 
   NS_ADDREF(*aChild = ToXPC(child));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetChildren(nsIArray** aChildren)
 {
   NS_ENSURE_ARG_POINTER(aChildren);
   *aChildren = nullptr;
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsIMutableArray> children =
     do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  uint32_t childCount = Intl()->ChildCount();
+  uint32_t childCount = IntlGeneric().ChildCount();
   for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
-    Accessible* child = Intl()->GetChildAt(childIdx);
+    AccessibleOrProxy child = IntlGeneric().ChildAt(childIdx);
     children->AppendElement(static_cast<nsIAccessible*>(ToXPC(child)), false);
   }
 
-  NS_ADDREF(*aChildren = children);
+  children.forget(aChildren);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetIndexInParent(int32_t* aIndexInParent)
 {
   NS_ENSURE_ARG_POINTER(aIndexInParent);
   *aIndexInParent = -1;
@@ -199,82 +200,107 @@ xpcAccessible::GetRootDocument(nsIAccess
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetRole(uint32_t* aRole)
 {
   NS_ENSURE_ARG_POINTER(aRole);
   *aRole = nsIAccessibleRole::ROLE_NOTHING;
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
-  *aRole = Intl()->Role();
+  *aRole = IntlGeneric().Role();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetState(uint32_t* aState, uint32_t* aExtraState)
 {
   NS_ENSURE_ARG_POINTER(aState);
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     nsAccUtils::To32States(states::DEFUNCT, aState, aExtraState);
+  else if (Intl())
+    nsAccUtils::To32States(Intl()->State(), aState, aExtraState);
   else
-    nsAccUtils::To32States(Intl()->State(), aState, aExtraState);
+    nsAccUtils::To32States(IntlGeneric().AsProxy()->State(), aState,
+                           aExtraState);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetName(nsAString& aName)
 {
   aName.Truncate();
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
   nsAutoString name;
-  Intl()->Name(name);
+  if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
+    proxy->Name(name);
+  } else {
+    Intl()->Name(name);
+  }
+
   aName.Assign(name);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetDescription(nsAString& aDescription)
 {
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
   nsAutoString desc;
-  Intl()->Description(desc);
+  if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
+    proxy->Description(desc);
+  } else {
+    Intl()->Description(desc);
+  }
+
   aDescription.Assign(desc);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetLanguage(nsAString& aLanguage)
 {
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
-  Intl()->Language(aLanguage);
+  nsAutoString lang;
+  if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
+    proxy->Language(lang);
+  } else {
+    Intl()->Language(lang);
+  }
+
+  aLanguage.Assign(lang);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetValue(nsAString& aValue)
 {
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
   nsAutoString value;
-  Intl()->Value(value);
+  if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
+    proxy->Value(value);
+  } else {
+    Intl()->Value(value);
+  }
+
   aValue.Assign(value);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetHelp(nsAString& aHelp)
 {
@@ -312,46 +338,69 @@ xpcAccessible::GetKeyboardShortcut(nsASt
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetAttributes(nsIPersistentProperties** aAttributes)
 {
   NS_ENSURE_ARG_POINTER(aAttributes);
   *aAttributes = nullptr;
 
-  if (!Intl())
+  if (IntlGeneric().IsNull()) {
     return NS_ERROR_FAILURE;
+  }
+
+  if (Accessible* acc = Intl()) {
+    nsCOMPtr<nsIPersistentProperties> attributes = acc->Attributes();
+    attributes.swap(*aAttributes);
+    return NS_OK;
+  }
 
-  nsCOMPtr<nsIPersistentProperties> attributes = Intl()->Attributes();
-  attributes.swap(*aAttributes);
+  ProxyAccessible* proxy = IntlGeneric().AsProxy();
+  AutoTArray<Attribute, 10> attrs;
+  proxy->Attributes(&attrs);
 
+  nsCOMPtr<nsIPersistentProperties> props =
+    do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
+  uint32_t attrCount = attrs.Length();
+  nsAutoString unused;
+  for (uint32_t i = 0; i < attrCount; i++) {
+    props->SetStringProperty(attrs[i].Name(), attrs[i].Value(), unused);
+  }
+
+  props.forget(aAttributes);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetBounds(int32_t* aX, int32_t* aY,
                          int32_t* aWidth, int32_t* aHeight)
 {
   NS_ENSURE_ARG_POINTER(aX);
   *aX = 0;
   NS_ENSURE_ARG_POINTER(aY);
   *aY = 0;
   NS_ENSURE_ARG_POINTER(aWidth);
   *aWidth = 0;
   NS_ENSURE_ARG_POINTER(aHeight);
   *aHeight = 0;
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
-  nsIntRect rect = Intl()->Bounds();
+  nsIntRect rect;
+  if (Accessible* acc = IntlGeneric().AsAccessible()) {
+    rect = acc->Bounds();
+  } else {
+    rect = IntlGeneric().AsProxy()->Bounds();
+  }
+
   *aX = rect.x;
   *aY = rect.y;
   *aWidth = rect.width;
-  *aHeight = rect.height;;
+  *aHeight = rect.height;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GroupPosition(int32_t* aGroupLevel,
                              int32_t* aSimilarItemsInGroup,
                              int32_t* aPositionInGroup)
--- a/accessible/xpcom/xpcAccessible.h
+++ b/accessible/xpcom/xpcAccessible.h
@@ -10,16 +10,17 @@
 #include "nsIAccessible.h"
 
 class nsIAccessible;
 
 namespace mozilla {
 namespace a11y {
 
 class Accessible;
+class AccessibleOrProxy;
 
 /**
  * XPCOM nsIAccessible interface implementation, used by xpcAccessibleGeneric
  * class.
  */
 class xpcAccessible : public nsIAccessible
 {
 public:
@@ -87,16 +88,17 @@ public:
                            int32_t aX, int32_t aY) final override;
 
 protected:
   xpcAccessible() { }
   virtual ~xpcAccessible() {}
 
 private:
   Accessible* Intl();
+  AccessibleOrProxy IntlGeneric();
 
   xpcAccessible(const xpcAccessible&) = delete;
   xpcAccessible& operator =(const xpcAccessible&) = delete;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/xpcom/xpcAccessibleApplication.h
+++ b/accessible/xpcom/xpcAccessibleApplication.h
@@ -31,17 +31,17 @@ public:
   NS_IMETHOD GetAppVersion(nsAString& aVersion) final override;
   NS_IMETHOD GetPlatformName(nsAString& aName) final override;
   NS_IMETHOD GetPlatformVersion(nsAString& aVersion) final override;
 
 protected:
   virtual ~xpcAccessibleApplication() {}
 
 private:
-  ApplicationAccessible* Intl() { return mIntl->AsApplication(); }
+  ApplicationAccessible* Intl() { return mIntl.AsAccessible()->AsApplication(); }
 
   xpcAccessibleApplication(const xpcAccessibleApplication&) = delete;
   xpcAccessibleApplication& operator =(const xpcAccessibleApplication&) = delete;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/xpcom/xpcAccessibleDocument.cpp
+++ b/accessible/xpcom/xpcAccessibleDocument.cpp
@@ -4,19 +4,21 @@
  * 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 "xpcAccessibleDocument.h"
 #include "xpcAccessibleImage.h"
 #include "xpcAccessibleTable.h"
 #include "xpcAccessibleTableCell.h"
 
+#include "mozilla/a11y/DocAccessibleParent.h"
 #include "DocAccessible-inl.h"
 #include "nsIDOMDocument.h"
 
+using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsISupports and cycle collection
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(xpcAccessibleDocument)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(xpcAccessibleDocument,
@@ -92,17 +94,17 @@ xpcAccessibleDocument::GetDOMDocument(ns
 
   if (Intl()->DocumentNode())
     CallQueryInterface(Intl()->DocumentNode(), aDOMDocument);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-xpcAccessibleDocument::GetWindow(nsIDOMWindow** aDOMWindow)
+xpcAccessibleDocument::GetWindow(mozIDOMWindowProxy** aDOMWindow)
 {
   NS_ENSURE_ARG_POINTER(aDOMWindow);
   *aDOMWindow = nullptr;
 
   if (!Intl())
     return NS_ERROR_FAILURE;
 
   NS_IF_ADDREF(*aDOMWindow = Intl()->DocumentNode()->GetWindow());
@@ -163,16 +165,17 @@ xpcAccessibleDocument::GetVirtualCursor(
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // xpcAccessibleDocument
 
 xpcAccessibleGeneric*
 xpcAccessibleDocument::GetAccessible(Accessible* aAccessible)
 {
+  MOZ_ASSERT(!mRemote);
   if (ToXPCDocument(aAccessible->Document()) != this) {
     NS_ERROR("This XPCOM document is not related with given internal accessible!");
     return nullptr;
   }
 
   if (aAccessible->IsDoc())
     return this;
 
@@ -190,17 +193,53 @@ xpcAccessibleDocument::GetAccessible(Acc
     xpcAcc = new xpcAccessibleHyperText(aAccessible);
   else
     xpcAcc = new xpcAccessibleGeneric(aAccessible);
 
   mCache.Put(aAccessible, xpcAcc);
   return xpcAcc;
 }
 
+xpcAccessibleGeneric*
+xpcAccessibleDocument::GetXPCAccessible(ProxyAccessible* aProxy)
+{
+  MOZ_ASSERT(mRemote);
+  MOZ_ASSERT(aProxy->Document() == mIntl.AsProxy());
+  if (aProxy->IsDoc()) {
+    return this;
+  }
+
+  xpcAccessibleGeneric* acc = mCache.GetWeak(aProxy);
+  if (acc) {
+    return acc;
+  }
+
+  // XXX support exposing optional interfaces.
+  acc = new xpcAccessibleGeneric(aProxy, 0);
+  mCache.Put(aProxy, acc);
+
+  return acc;
+}
+
 void
 xpcAccessibleDocument::Shutdown()
 {
   for (auto iter = mCache.Iter(); !iter.Done(); iter.Next()) {
     iter.Data()->Shutdown();
     iter.Remove();
   }
   xpcAccessibleGeneric::Shutdown();
 }
+
+xpcAccessibleGeneric*
+a11y::ToXPC(AccessibleOrProxy aAcc)
+{
+  if (aAcc.IsNull()) {
+    return nullptr;
+  }
+
+  if (aAcc.IsAccessible()) {
+    return ToXPC(aAcc.AsAccessible());
+  }
+
+ xpcAccessibleDocument* doc = ToXPCDocument(aAcc.AsProxy()->Document());
+ return doc->GetXPCAccessible(aAcc.AsProxy());
+}
--- a/accessible/xpcom/xpcAccessibleDocument.h
+++ b/accessible/xpcom/xpcAccessibleDocument.h
@@ -20,83 +20,111 @@ namespace a11y {
 /**
  * XPCOM wrapper around DocAccessible class.
  */
 class xpcAccessibleDocument : public xpcAccessibleHyperText,
                               public nsIAccessibleDocument
 {
 public:
   explicit xpcAccessibleDocument(DocAccessible* aIntl) :
-    xpcAccessibleHyperText(aIntl), mCache(kDefaultCacheLength) { }
+    xpcAccessibleHyperText(aIntl), mCache(kDefaultCacheLength), mRemote(false) { }
+
+  xpcAccessibleDocument(ProxyAccessible* aProxy, uint32_t aInterfaces) :
+    xpcAccessibleHyperText(aProxy, aInterfaces), mCache(kDefaultCacheLength),
+    mRemote(true) {}
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(xpcAccessibleDocument,
                                            xpcAccessibleGeneric)
 
   // nsIAccessibleDocument
   NS_IMETHOD GetURL(nsAString& aURL) final override;
   NS_IMETHOD GetTitle(nsAString& aTitle) final override;
   NS_IMETHOD GetMimeType(nsAString& aType) final override;
   NS_IMETHOD GetDocType(nsAString& aType) final override;
   NS_IMETHOD GetDOMDocument(nsIDOMDocument** aDOMDocument) final override;
-  NS_IMETHOD GetWindow(nsIDOMWindow** aDOMWindow) final override;
+  NS_IMETHOD GetWindow(mozIDOMWindowProxy** aDOMWindow) final override;
   NS_IMETHOD GetParentDocument(nsIAccessibleDocument** aDocument)
     final override;
   NS_IMETHOD GetChildDocumentCount(uint32_t* aCount) final override;
   NS_IMETHOD GetChildDocumentAt(uint32_t aIndex,
                                 nsIAccessibleDocument** aDocument)
     final override;
   NS_IMETHOD GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor)
     final override;
 
   /**
    * Return XPCOM wrapper for the internal accessible.
    */
   xpcAccessibleGeneric* GetAccessible(Accessible* aAccessible);
+  xpcAccessibleGeneric* GetXPCAccessible(ProxyAccessible* aProxy);
 
   virtual void Shutdown() override;
 
 protected:
   virtual ~xpcAccessibleDocument() {}
 
 private:
-  DocAccessible* Intl() { return mIntl->AsDoc(); }
+  DocAccessible* Intl()
+  {
+    if (Accessible* acc = mIntl.AsAccessible()) {
+      return acc->AsDoc();
+    }
+
+    return nullptr;
+  }
 
   void NotifyOfShutdown(Accessible* aAccessible)
   {
+    MOZ_ASSERT(!mRemote);
     xpcAccessibleGeneric* xpcAcc = mCache.GetWeak(aAccessible);
     if (xpcAcc)
       xpcAcc->Shutdown();
 
     mCache.Remove(aAccessible);
   }
 
+  void NotifyOfShutdown(ProxyAccessible* aProxy)
+  {
+    MOZ_ASSERT(mRemote);
+    xpcAccessibleGeneric* acc = mCache.GetWeak(aProxy);
+    if (acc) {
+      acc->Shutdown();
+    }
+
+    mCache.Remove(aProxy);
+  }
+
   friend class DocManager;
   friend class DocAccessible;
+  friend class ProxyAccessible;
 
   xpcAccessibleDocument(const xpcAccessibleDocument&) = delete;
   xpcAccessibleDocument& operator =(const xpcAccessibleDocument&) = delete;
 
-  nsRefPtrHashtable<nsPtrHashKey<const Accessible>, xpcAccessibleGeneric> mCache;
+  nsRefPtrHashtable<nsPtrHashKey<const void>, xpcAccessibleGeneric> mCache;
+  bool mRemote;
 };
 
 inline xpcAccessibleGeneric*
 ToXPC(Accessible* aAccessible)
 {
   if (!aAccessible)
     return nullptr;
 
   if (aAccessible->IsApplication())
     return XPCApplicationAcc();
 
   xpcAccessibleDocument* xpcDoc =
     GetAccService()->GetXPCDocument(aAccessible->Document());
   return xpcDoc ? xpcDoc->GetAccessible(aAccessible) : nullptr;
 }
 
+xpcAccessibleGeneric* ToXPC(AccessibleOrProxy aAcc);
+
 inline xpcAccessibleHyperText*
 ToXPCText(HyperTextAccessible* aAccessible)
 {
   if (!aAccessible)
     return nullptr;
 
   xpcAccessibleDocument* xpcDoc =
     GetAccService()->GetXPCDocument(aAccessible->Document());
@@ -104,12 +132,18 @@ ToXPCText(HyperTextAccessible* aAccessib
 }
 
 inline xpcAccessibleDocument*
 ToXPCDocument(DocAccessible* aAccessible)
 {
   return GetAccService()->GetXPCDocument(aAccessible);
 }
 
+inline xpcAccessibleDocument*
+ToXPCDocument(DocAccessibleParent* aAccessible)
+{
+  return GetAccService()->GetXPCDocument(aAccessible);
+}
+
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/xpcom/xpcAccessibleGeneric.cpp
+++ b/accessible/xpcom/xpcAccessibleGeneric.cpp
@@ -28,17 +28,17 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(xpcAcces
 NS_IMPL_CYCLE_COLLECTING_RELEASE(xpcAccessibleGeneric)
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIAccessible
 
 Accessible*
 xpcAccessibleGeneric::ToInternalAccessible() const
 {
-  return mIntl;
+  return mIntl.AsAccessible();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // xpcAccessibleGeneric
 
 void
 xpcAccessibleGeneric::Shutdown()
 {
--- a/accessible/xpcom/xpcAccessibleGeneric.h
+++ b/accessible/xpcom/xpcAccessibleGeneric.h
@@ -8,53 +8,68 @@
 #define mozilla_a11y_xpcAccessibleGeneric_h_
 
 #include "xpcAccessible.h"
 #include "xpcAccessibleHyperLink.h"
 #include "xpcAccessibleSelectable.h"
 #include "xpcAccessibleValue.h"
 
 #include "Accessible.h"
+#include "AccessibleOrProxy.h"
 
 namespace mozilla {
 namespace a11y {
 
 /**
  * XPCOM wrapper around Accessible class.
  */
 class xpcAccessibleGeneric : public xpcAccessible,
                              public xpcAccessibleHyperLink,
                              public xpcAccessibleSelectable,
                              public xpcAccessibleValue
 {
 public:
   explicit xpcAccessibleGeneric(Accessible* aInternal) :
     mIntl(aInternal), mSupportedIfaces(0)
   {
-    if (mIntl->IsSelect())
+    if (aInternal->IsSelect())
       mSupportedIfaces |= eSelectable;
-    if (mIntl->HasNumericValue())
+    if (aInternal->HasNumericValue())
       mSupportedIfaces |= eValue;
-    if (mIntl->IsLink())
+    if (aInternal->IsLink())
       mSupportedIfaces |= eHyperLink;
   }
 
+  xpcAccessibleGeneric(ProxyAccessible* aProxy, uint32_t aInterfaces) :
+    mIntl(aProxy), mSupportedIfaces(0)
+  {
+    if (aInterfaces & Interfaces::SELECTION) {
+      mSupportedIfaces |= eSelectable;
+    }
+      if (aInterfaces & Interfaces::VALUE) {
+        mSupportedIfaces |= eValue;
+      }
+      if (aInterfaces & Interfaces::HYPERLINK) {
+        mSupportedIfaces |= eHyperLink;
+      }
+    }
+
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(xpcAccessibleGeneric, nsIAccessible)
 
   // nsIAccessible
   virtual Accessible* ToInternalAccessible() const final override;
 
   // xpcAccessibleGeneric
   virtual void Shutdown();
 
 protected:
   virtual ~xpcAccessibleGeneric() {}
 
-  Accessible* mIntl;
+  AccessibleOrProxy mIntl;
 
   enum {
     eSelectable = 1 << 0,
     eValue = 1 << 1,
     eHyperLink = 1 << 2,
     eText = 1 << 3
   };
   uint8_t mSupportedIfaces;
@@ -68,33 +83,39 @@ private:
 
   xpcAccessibleGeneric(const xpcAccessibleGeneric&) = delete;
   xpcAccessibleGeneric& operator =(const xpcAccessibleGeneric&) = delete;
 };
 
 inline Accessible*
 xpcAccessible::Intl()
 {
+  return static_cast<xpcAccessibleGeneric*>(this)->mIntl.AsAccessible();
+}
+
+inline AccessibleOrProxy
+xpcAccessible::IntlGeneric()
+{
   return static_cast<xpcAccessibleGeneric*>(this)->mIntl;
 }
 
 inline Accessible*
 xpcAccessibleHyperLink::Intl()
 {
-  return static_cast<xpcAccessibleGeneric*>(this)->mIntl;
+  return static_cast<xpcAccessibleGeneric*>(this)->mIntl.AsAccessible();
 }
 
 inline Accessible*
 xpcAccessibleSelectable::Intl()
 {
-  return static_cast<xpcAccessibleGeneric*>(this)->mIntl;
+  return static_cast<xpcAccessibleGeneric*>(this)->mIntl.AsAccessible();
 }
 
 inline Accessible*
 xpcAccessibleValue::Intl()
 {
-  return static_cast<xpcAccessibleGeneric*>(this)->mIntl;
+  return static_cast<xpcAccessibleGeneric*>(this)->mIntl.AsAccessible();
 }
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/xpcom/xpcAccessibleHyperText.cpp
+++ b/accessible/xpcom/xpcAccessibleHyperText.cpp
@@ -366,17 +366,17 @@ xpcAccessibleHyperText::GetSelectionRang
   if (!Intl())
     return NS_ERROR_FAILURE;
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsIMutableArray> xpcRanges =
     do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsAutoTArray<TextRange, 1> ranges;
+  AutoTArray<TextRange, 1> ranges;
   Intl()->SelectionRanges(&ranges);
   uint32_t len = ranges.Length();
   for (uint32_t idx = 0; idx < len; idx++)
     xpcRanges->AppendElement(new xpcAccessibleTextRange(Move(ranges[idx])),
                              false);
 
   xpcRanges.forget(aRanges);
   return NS_OK;
--- a/accessible/xpcom/xpcAccessibleHyperText.h
+++ b/accessible/xpcom/xpcAccessibleHyperText.h
@@ -21,31 +21,41 @@ class xpcAccessibleHyperText : public xp
                                public nsIAccessibleText,
                                public nsIAccessibleEditableText,
                                public nsIAccessibleHyperText
 {
 public:
   explicit xpcAccessibleHyperText(Accessible* aIntl) :
     xpcAccessibleGeneric(aIntl)
   {
-    if (mIntl->IsHyperText() && mIntl->AsHyperText()->IsTextRole())
+    if (aIntl->IsHyperText() && aIntl->AsHyperText()->IsTextRole())
       mSupportedIfaces |= eText;
   }
 
+  xpcAccessibleHyperText(ProxyAccessible* aProxy, uint32_t aInterfaces) :
+    xpcAccessibleGeneric(aProxy, aInterfaces) { mSupportedIfaces |= eText; }
+
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIACCESSIBLETEXT
   NS_DECL_NSIACCESSIBLEHYPERTEXT
   NS_DECL_NSIACCESSIBLEEDITABLETEXT
 
 protected:
   virtual ~xpcAccessibleHyperText() {}
 
 private:
-  HyperTextAccessible* Intl() { return mIntl->AsHyperText(); }
+  HyperTextAccessible* Intl()
+  {
+    if (Accessible* acc = mIntl.AsAccessible()) {
+      return acc->AsHyperText();
+    }
+
+    return nullptr;
+  }
 
   xpcAccessibleHyperText(const xpcAccessibleHyperText&) = delete;
   xpcAccessibleHyperText& operator =(const xpcAccessibleHyperText&) = delete;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/xpcom/xpcAccessibleImage.h
+++ b/accessible/xpcom/xpcAccessibleImage.h
@@ -16,27 +16,31 @@ namespace a11y {
 
 class xpcAccessibleImage : public xpcAccessibleGeneric,
                            public nsIAccessibleImage
 {
 public:
   explicit xpcAccessibleImage(Accessible* aIntl) :
     xpcAccessibleGeneric(aIntl) { }
 
+  xpcAccessibleImage(ProxyAccessible* aProxy, uint32_t aInterfaces) :
+    xpcAccessibleGeneric(aProxy, aInterfaces) {}
+
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_IMETHOD GetImagePosition(uint32_t aCoordType,
                               int32_t* aX, int32_t* aY) final override;
   NS_IMETHOD GetImageSize(int32_t* aWidth, int32_t* aHeight) final override;
 
 protected:
   virtual ~xpcAccessibleImage() {}
 
 private:
-  ImageAccessible* Intl() { return mIntl->AsImage(); }
+  ImageAccessible* Intl()
+  { return mIntl.IsAccessible() ? mIntl.AsAccessible()->AsImage() : nullptr; }
 
   xpcAccessibleImage(const xpcAccessibleImage&) = delete;
   xpcAccessibleImage& operator =(const xpcAccessibleImage&) = delete;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/xpcom/xpcAccessibleSelectable.cpp
+++ b/accessible/xpcom/xpcAccessibleSelectable.cpp
@@ -16,17 +16,17 @@ xpcAccessibleSelectable::GetSelectedItem
 {
   NS_ENSURE_ARG_POINTER(aSelectedItems);
   *aSelectedItems = nullptr;
 
   if (!Intl())
     return NS_ERROR_FAILURE;
   NS_PRECONDITION(Intl()->IsSelect(), "Called on non selectable widget!");
 
-  nsAutoTArray<Accessible*, 10> items;
+  AutoTArray<Accessible*, 10> items;
   Intl()->SelectedItems(&items);
 
   uint32_t itemCount = items.Length();
   if (itemCount == 0)
     return NS_OK;
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsIMutableArray> xpcItems =
--- a/accessible/xpcom/xpcAccessibleTable.cpp
+++ b/accessible/xpcom/xpcAccessibleTable.cpp
@@ -268,17 +268,17 @@ xpcAccessibleTable::GetSelectedCells(nsI
   if (!Intl())
     return NS_ERROR_FAILURE;
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsIMutableArray> selCells =
     do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsAutoTArray<Accessible*, XPC_TABLE_DEFAULT_SIZE> cellsArray;
+  AutoTArray<Accessible*, XPC_TABLE_DEFAULT_SIZE> cellsArray;
   Intl()->SelectedCells(&cellsArray);
 
   uint32_t totalCount = cellsArray.Length();
   for (uint32_t idx = 0; idx < totalCount; idx++) {
     Accessible* cell = cellsArray.ElementAt(idx);
     selCells->AppendElement(static_cast<nsIAccessible*>(ToXPC(cell)), false);
   }
 
@@ -294,17 +294,17 @@ xpcAccessibleTable::GetSelectedCellIndic
   *aCellsArraySize = 0;
 
   NS_ENSURE_ARG_POINTER(aCellsArray);
   *aCellsArray = 0;
 
   if (!Intl())
     return NS_ERROR_FAILURE;
 
-  nsAutoTArray<uint32_t, XPC_TABLE_DEFAULT_SIZE> cellsArray;
+  AutoTArray<uint32_t, XPC_TABLE_DEFAULT_SIZE> cellsArray;
   Intl()->SelectedCellIndices(&cellsArray);
 
   *aCellsArraySize = cellsArray.Length();
   *aCellsArray = static_cast<int32_t*>
     (moz_xmalloc(*aCellsArraySize * sizeof(int32_t)));
   memcpy(*aCellsArray, cellsArray.Elements(),
     *aCellsArraySize * sizeof(int32_t));
 
@@ -319,17 +319,17 @@ xpcAccessibleTable::GetSelectedColumnInd
   *aColsArraySize = 0;
 
   NS_ENSURE_ARG_POINTER(aColsArray);
   *aColsArray = 0;
 
   if (!Intl())
     return NS_ERROR_FAILURE;
 
-  nsAutoTArray<uint32_t, XPC_TABLE_DEFAULT_SIZE> colsArray;
+  AutoTArray<uint32_t, XPC_TABLE_DEFAULT_SIZE> colsArray;
   Intl()->SelectedColIndices(&colsArray);
 
   *aColsArraySize = colsArray.Length();
   *aColsArray = static_cast<int32_t*>
     (moz_xmalloc(*aColsArraySize * sizeof(int32_t)));
   memcpy(*aColsArray, colsArray.Elements(),
     *aColsArraySize * sizeof(int32_t));
 
@@ -344,17 +344,17 @@ xpcAccessibleTable::GetSelectedRowIndice
   *aRowsArraySize = 0;
 
   NS_ENSURE_ARG_POINTER(aRowsArray);
   *aRowsArray = 0;
 
   if (!Intl())
     return NS_ERROR_FAILURE;
 
-  nsAutoTArray<uint32_t, XPC_TABLE_DEFAULT_SIZE> rowsArray;
+  AutoTArray<uint32_t, XPC_TABLE_DEFAULT_SIZE> rowsArray;
   Intl()->SelectedRowIndices(&rowsArray);
 
   *aRowsArraySize = rowsArray.Length();
   *aRowsArray = static_cast<int32_t*>
     (moz_xmalloc(*aRowsArraySize * sizeof(int32_t)));
   memcpy(*aRowsArray, rowsArray.Elements(),
     *aRowsArraySize * sizeof(int32_t));
 
--- a/accessible/xpcom/xpcAccessibleTable.h
+++ b/accessible/xpcom/xpcAccessibleTable.h
@@ -18,16 +18,19 @@ namespace a11y {
  */
 class xpcAccessibleTable : public xpcAccessibleGeneric,
                            public nsIAccessibleTable
 {
 public:
   explicit xpcAccessibleTable(Accessible* aIntl) :
     xpcAccessibleGeneric(aIntl) { }
 
+  xpcAccessibleTable(ProxyAccessible* aProxy, uint32_t aInterfaces) :
+    xpcAccessibleGeneric(aProxy, aInterfaces) {}
+
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessibleTable
   NS_IMETHOD GetCaption(nsIAccessible** aCaption) final override;
   NS_IMETHOD GetSummary(nsAString& aSummary) final override;
   NS_IMETHOD GetColumnCount(int32_t* aColumnCount) final override;
   NS_IMETHOD GetRowCount(int32_t* aRowCount) final override;
   NS_IMETHOD GetCellAt(int32_t aRowIndex, int32_t aColumnIndex,
@@ -75,17 +78,18 @@ public:
   NS_IMETHOD UnselectColumn(int32_t aColIdx) final override;
   NS_IMETHOD UnselectRow(int32_t aRowIdx) final override;
   NS_IMETHOD IsProbablyForLayout(bool* aIsForLayout) final override;
 
 protected:
   virtual ~xpcAccessibleTable() {}
 
 private:
-  TableAccessible* Intl() { return mIntl->AsTable(); }
+  TableAccessible* Intl()
+  { return mIntl.IsAccessible() ? mIntl.AsAccessible()->AsTable() : nullptr; }
 
   xpcAccessibleTable(const xpcAccessibleTable&) = delete;
   xpcAccessibleTable& operator =(const xpcAccessibleTable&) = delete;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/xpcom/xpcAccessibleTableCell.cpp
+++ b/accessible/xpcom/xpcAccessibleTableCell.cpp
@@ -103,17 +103,17 @@ NS_IMETHODIMP
 xpcAccessibleTableCell::GetColumnHeaderCells(nsIArray** aHeaderCells)
 {
   NS_ENSURE_ARG_POINTER(aHeaderCells);
   *aHeaderCells = nullptr;
 
   if (!Intl())
     return NS_ERROR_FAILURE;
 
-  nsAutoTArray<Accessible*, 10> headerCells;
+  AutoTArray<Accessible*, 10> headerCells;
   Intl()->ColHeaderCells(&headerCells);
 
   nsCOMPtr<nsIMutableArray> cells = do_CreateInstance(NS_ARRAY_CONTRACTID);
   NS_ENSURE_TRUE(cells, NS_ERROR_FAILURE);
 
   for (uint32_t idx = 0; idx < headerCells.Length(); idx++) {
     cells->AppendElement(static_cast<nsIAccessible*>(ToXPC(headerCells[idx])),
                          false);
@@ -127,17 +127,17 @@ NS_IMETHODIMP
 xpcAccessibleTableCell::GetRowHeaderCells(nsIArray** aHeaderCells)
 {
   NS_ENSURE_ARG_POINTER(aHeaderCells);
   *aHeaderCells = nullptr;
 
   if (!Intl())
     return NS_ERROR_FAILURE;
 
-  nsAutoTArray<Accessible*, 10> headerCells;
+  AutoTArray<Accessible*, 10> headerCells;
   Intl()->RowHeaderCells(&headerCells);
 
   nsCOMPtr<nsIMutableArray> cells = do_CreateInstance(NS_ARRAY_CONTRACTID);
   NS_ENSURE_TRUE(cells, NS_ERROR_FAILURE);
 
   for (uint32_t idx = 0; idx < headerCells.Length(); idx++) {
     cells->AppendElement(static_cast<nsIAccessible*>(ToXPC(headerCells[idx])),
                          false);
--- a/accessible/xpcom/xpcAccessibleTableCell.h
+++ b/accessible/xpcom/xpcAccessibleTableCell.h
@@ -19,33 +19,43 @@ namespace a11y {
  */
 class xpcAccessibleTableCell : public xpcAccessibleHyperText,
                                public nsIAccessibleTableCell
 {
 public:
   explicit xpcAccessibleTableCell(Accessible* aIntl) :
     xpcAccessibleHyperText(aIntl) { }
 
+  xpcAccessibleTableCell(ProxyAccessible* aProxy, uint32_t aInterfaces) :
+    xpcAccessibleHyperText(aProxy, aInterfaces) {}
+
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessibleTableCell
   NS_IMETHOD GetTable(nsIAccessibleTable** aTable) final override;
   NS_IMETHOD GetColumnIndex(int32_t* aColIdx) final override;
   NS_IMETHOD GetRowIndex(int32_t* aRowIdx) final override;
   NS_IMETHOD GetColumnExtent(int32_t* aExtent) final override;
   NS_IMETHOD GetRowExtent(int32_t* aExtent) final override;
   NS_IMETHOD GetColumnHeaderCells(nsIArray** aHeaderCells) final override;
   NS_IMETHOD GetRowHeaderCells(nsIArray** aHeaderCells) final override;
   NS_IMETHOD IsSelected(bool* aSelected) final override;
 
 protected:
   virtual ~xpcAccessibleTableCell() {}
 
 private:
-  TableCellAccessible* Intl() { return mIntl->AsTableCell(); }
+  TableCellAccessible* Intl()
+  {
+    if (Accessible* acc = mIntl.AsAccessible()) {
+      return acc->AsTableCell();
+    }
+
+    return nullptr;
+}
 
   xpcAccessibleTableCell(const xpcAccessibleTableCell&) = delete;
   xpcAccessibleTableCell& operator =(const xpcAccessibleTableCell&) = delete;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/xpcom/xpcAccessibleTextRange.cpp
+++ b/accessible/xpcom/xpcAccessibleTextRange.cpp
@@ -1,17 +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 "xpcAccessibleTextRange.h"
 
-#include "TextRange.h"
+#include "TextRange-inl.h"
 #include "xpcAccessibleDocument.h"
 
 #include "nsIMutableArray.h"
 #include "nsComponentManagerUtils.h"
 #include "nsQueryObject.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
@@ -166,16 +166,26 @@ xpcAccessibleTextRange::MoveEnd(uint32_t
 
 NS_IMETHODIMP
 xpcAccessibleTextRange::Normalize(uint32_t aUnit)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
+xpcAccessibleTextRange::Crop(nsIAccessible* aContainer, bool* aSuccess)
+{
+  Accessible* container = aContainer->ToInternalAccessible();
+  NS_ENSURE_TRUE(container, NS_ERROR_INVALID_ARG);
+
+  *aSuccess = mRange.Crop(container);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 xpcAccessibleTextRange::FindText(const nsAString& aText, bool aIsBackward,
                                  bool aIsIgnoreCase,
                                  nsIAccessibleTextRange** aRange)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/accessible/xpcom/xpcAccessibleTextRange.h
+++ b/accessible/xpcom/xpcAccessibleTextRange.h
@@ -44,16 +44,17 @@ public:
                               uint32_t aOtherRangeEndPoint,
                               int32_t* aResult) final override;
   NS_IMETHOD GetText(nsAString& aText) final override;
   NS_IMETHOD GetBounds(nsIArray** aRectList) final override;
   NS_IMETHOD Move(uint32_t aUnit, int32_t aCount) final override;
   NS_IMETHOD MoveStart(uint32_t aUnit, int32_t aCount) final override;
   NS_IMETHOD MoveEnd(uint32_t aUnit, int32_t aCount) final override;
   NS_IMETHOD Normalize(uint32_t aUnit) final override;
+  NS_IMETHOD Crop(nsIAccessible* aContainer, bool* aSuccess) final override;
   NS_IMETHOD FindText(const nsAString& aText, bool aIsBackward, bool aIsIgnoreCase,
                       nsIAccessibleTextRange** aRange) final override;
   NS_IMETHOD FindAttr(uint32_t aAttr, nsIVariant* aVal, bool aIsBackward,
                       nsIAccessibleTextRange** aRange) final override;
   NS_IMETHOD AddToSelection() final override;
   NS_IMETHOD RemoveFromSelection() final override;
   NS_IMETHOD Select() final override;
   NS_IMETHOD ScrollIntoView(uint32_t aHow) final override;
--- a/accessible/xul/XULAlertAccessible.cpp
+++ b/accessible/xul/XULAlertAccessible.cpp
@@ -14,16 +14,17 @@ using namespace mozilla::a11y;
 ////////////////////////////////////////////////////////////////////////////////
 // XULAlertAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 XULAlertAccessible::
   XULAlertAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   AccessibleWrap(aContent, aDoc)
 {
+  mGenericTypes |= eAlert;
 }
 
 XULAlertAccessible::~XULAlertAccessible()
 {
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(XULAlertAccessible, Accessible)
 
--- a/accessible/xul/XULColorPickerAccessible.cpp
+++ b/accessible/xul/XULColorPickerAccessible.cpp
@@ -125,15 +125,19 @@ XULColorPickerAccessible::AreItemsOperab
   if (menuPopup) {
     nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(menuPopup->GetFrame());
     return menuPopupFrame && menuPopupFrame->IsOpen();
   }
   return false;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// XULColorPickerAccessible: protected Accessible
+// XULColorPickerAccessible: Accessible
 
 bool
-XULColorPickerAccessible::IsAcceptableChild(Accessible* aPossibleChild) const
+XULColorPickerAccessible::IsAcceptableChild(nsIContent* aEl) const
 {
-  return roles::ALERT == aPossibleChild->Role();
+  nsAutoString role;
+  nsCoreUtils::XBLBindingRole(aEl, role);
+  return role.EqualsLiteral("xul:panel") &&
+    aEl->AttrValueIs(kNameSpaceID_None, nsGkAtoms::noautofocus,
+                     nsGkAtoms::_true, eCaseMatters);
 }
--- a/accessible/xul/XULColorPickerAccessible.h
+++ b/accessible/xul/XULColorPickerAccessible.h
@@ -43,15 +43,15 @@ public:
   virtual a11y::role NativeRole() override;
   virtual uint64_t NativeState() override;
 
   // Widgets
   virtual bool IsWidget() const override;
   virtual bool IsActiveWidget() const override;
   virtual bool AreItemsOperable() const override;
 
-  virtual bool IsAcceptableChild(Accessible* aPossibleChild) const override;
+  virtual bool IsAcceptableChild(nsIContent* aEl) const override;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif  
--- a/accessible/xul/XULComboboxAccessible.cpp
+++ b/accessible/xul/XULComboboxAccessible.cpp
@@ -26,16 +26,25 @@ XULComboboxAccessible::
   XULComboboxAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   AccessibleWrap(aContent, aDoc)
 {
   if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
                             nsGkAtoms::autocomplete, eIgnoreCase))
     mGenericTypes |= eAutoComplete;
   else
     mGenericTypes |= eCombobox;
+
+  // Both the XUL <textbox type="autocomplete"> and <menulist editable="true">
+  // widgets use XULComboboxAccessible. We need to walk the anonymous children
+  // for these so that the entry field is a child. Otherwise no XBL children.
+  if (!mContent->NodeInfo()->Equals(nsGkAtoms::textbox, kNameSpaceID_XUL) &&
+      !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
+                             nsGkAtoms::_true, eIgnoreCase)) {
+    mStateFlags |= eNoXBLKids;
+  }
 }
 
 role
 XULComboboxAccessible::NativeRole()
 {
   return IsAutoComplete() ? roles::AUTOCOMPLETE : roles::COMBOBOX;
 }
 
@@ -91,33 +100,16 @@ XULComboboxAccessible::Value(nsString& a
   aValue.Truncate();
 
   // The value is the option or text shown entered in the combobox.
   nsCOMPtr<nsIDOMXULMenuListElement> menuList(do_QueryInterface(mContent));
   if (menuList)
     menuList->GetLabel(aValue);
 }
 
-bool
-XULComboboxAccessible::CanHaveAnonChildren()
-{
-  if (mContent->NodeInfo()->Equals(nsGkAtoms::textbox, kNameSpaceID_XUL) ||
-      mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
-                            nsGkAtoms::_true, eIgnoreCase)) {
-    // Both the XUL <textbox type="autocomplete"> and <menulist editable="true"> widgets
-    // use XULComboboxAccessible. We need to walk the anonymous children for these
-    // so that the entry field is a child
-    return true;
-  }
-
-  // Argument of false indicates we don't walk anonymous children for
-  // menuitems
-  return false;
-}
-
 uint8_t
 XULComboboxAccessible::ActionCount()
 {
   // Just one action (click).
   return 1;
 }
 
 bool
--- a/accessible/xul/XULComboboxAccessible.h
+++ b/accessible/xul/XULComboboxAccessible.h
@@ -21,17 +21,16 @@ public:
 
   XULComboboxAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
   virtual void Description(nsString& aDescription) override;
   virtual void Value(nsString& aValue) override;
   virtual a11y::role NativeRole() override;
   virtual uint64_t NativeState() override;
-  virtual bool CanHaveAnonChildren() override;
 
   // ActionAccessible
   virtual uint8_t ActionCount() override;
   virtual void ActionNameAt(uint8_t aIndex, nsAString& aName) override;
   virtual bool DoAction(uint8_t aIndex) override;
 
   // Widgets
   virtual bool IsActiveWidget() const override;
--- a/accessible/xul/XULFormControlAccessible.cpp
+++ b/accessible/xul/XULFormControlAccessible.cpp
@@ -160,35 +160,39 @@ Accessible*
 XULButtonAccessible::ContainerWidget() const
 {
   if (IsMenuButton() && mParent && mParent->IsAutoComplete())
     return mParent;
   return nullptr;
 }
 
 bool
-XULButtonAccessible::IsAcceptableChild(Accessible* aPossibleChild) const
+XULButtonAccessible::IsAcceptableChild(nsIContent* aEl) const
 {
   // In general XUL button has not accessible children. Nevertheless menu
   // buttons can have button (@type="menu-button") and popup accessibles
   // (@type="menu-button", @type="menu" or columnpicker.
 
   // XXX: no children until the button is menu button. Probably it's not
   // totally correct but in general AT wants to have leaf buttons.
-  roles::Role role = aPossibleChild->Role();
+  nsAutoString role;
+  nsCoreUtils::XBLBindingRole(aEl, role);
 
   // Get an accessible for menupopup or panel elements.
-  if (role == roles::MENUPOPUP)
+  if (role.EqualsLiteral("xul:menupopup")) {
     return true;
+  }
 
   // Button type="menu-button" contains a real button. Get an accessible
   // for it. Ignore dropmarker button which is placed as a last child.
-  if (role != roles::PUSHBUTTON ||
-      aPossibleChild->GetContent()->IsXULElement(nsGkAtoms::dropMarker))
+  if ((!role.EqualsLiteral("xul:button") &&
+       !role.EqualsLiteral("xul:toolbarbutton")) ||
+      aEl->IsXULElement(nsGkAtoms::dropMarker)) {
     return false;
+  }
 
   return mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
                                nsGkAtoms::menuButton, eCaseMatters);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULButtonAccessible protected
 
--- a/accessible/xul/XULFormControlAccessible.h
+++ b/accessible/xul/XULFormControlAccessible.h
@@ -45,17 +45,17 @@ public:
   virtual bool DoAction(uint8_t aIndex) override;
 
   // Widgets
   virtual bool IsWidget() const override;
   virtual bool IsActiveWidget() const override;
   virtual bool AreItemsOperable() const override;
   virtual Accessible* ContainerWidget() const override;
 
-  virtual bool IsAcceptableChild(Accessible* aPossibleChild) const override;
+  virtual bool IsAcceptableChild(nsIContent* aEl) const override;
 
 protected:
   virtual ~XULButtonAccessible();
 
   // XULButtonAccessible
   bool ContainsMenu() const;
 };
 
--- a/accessible/xul/XULListboxAccessible.cpp
+++ b/accessible/xul/XULListboxAccessible.cpp
@@ -539,16 +539,20 @@ XULListitemAccessible::
   XULListitemAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   XULMenuitemAccessible(aContent, aDoc)
 {
   mIsCheckbox = mContent->AttrValueIs(kNameSpaceID_None,
                                       nsGkAtoms::type,
                                       nsGkAtoms::checkbox,
                                       eCaseMatters);
   mType = eXULListItemType;
+
+  // Walk XBL anonymous children for list items. Overrides the flag value from
+  // base XULMenuitemAccessible class.
+  mStateFlags &= ~eNoXBLKids;
 }
 
 XULListitemAccessible::~XULListitemAccessible()
 {
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(XULListitemAccessible, Accessible)
 
@@ -663,23 +667,16 @@ XULListitemAccessible::ActionNameAt(uint
     uint64_t states = NativeState();
     if (states & states::CHECKED)
       aName.AssignLiteral("uncheck");
     else
       aName.AssignLiteral("check");
   }
 }
 
-bool
-XULListitemAccessible::CanHaveAnonChildren()
-{
-  // That indicates we should walk anonymous children for listitems
-  return true;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // XULListitemAccessible: Widgets
 
 Accessible*
 XULListitemAccessible::ContainerWidget() const
 {
   return Parent();
 }
--- a/accessible/xul/XULListboxAccessible.h
+++ b/accessible/xul/XULListboxAccessible.h
@@ -110,17 +110,16 @@ public:
 
   XULListitemAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
   virtual void Description(nsString& aDesc) override;
   virtual a11y::role NativeRole() override;
   virtual uint64_t NativeState() override;
   virtual uint64_t NativeInteractiveState() const override;
-  virtual bool CanHaveAnonChildren() override;
 
   // Actions
   virtual void ActionNameAt(uint8_t index, nsAString& aName) override;
 
   // Widgets
   virtual Accessible* ContainerWidget() const override;
 
 protected:
--- a/accessible/xul/XULMenuAccessible.cpp
+++ b/accessible/xul/XULMenuAccessible.cpp
@@ -36,16 +36,17 @@ using namespace mozilla::a11y;
 ////////////////////////////////////////////////////////////////////////////////
 // XULMenuitemAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 XULMenuitemAccessible::
   XULMenuitemAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   AccessibleWrap(aContent, aDoc)
 {
+  mStateFlags |= eNoXBLKids;
 }
 
 uint64_t
 XULMenuitemAccessible::NativeState()
 {
   uint64_t state = Accessible::NativeState();
 
   // Has Popup?
@@ -263,23 +264,16 @@ XULMenuitemAccessible::NativeRole()
 
 int32_t
 XULMenuitemAccessible::GetLevelInternal()
 {
   return nsAccUtils::GetLevelForXULContainerItem(mContent);
 }
 
 bool
-XULMenuitemAccessible::CanHaveAnonChildren()
-{
-  // That indicates we don't walk anonymous children for menuitems
-  return false;
-}
-
-bool
 XULMenuitemAccessible::DoAction(uint8_t index)
 {
   if (index == eAction_Click) {   // default action
     DoCommand();
     return true;
   }
 
   return false;
@@ -408,16 +402,18 @@ XULMenupopupAccessible::
   nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(GetFrame());
   if (menuPopupFrame && menuPopupFrame->IsMenu())
     mType = eMenuPopupType;
 
   // May be the anonymous <menupopup> inside <menulist> (a combobox)
   mSelectControl = do_QueryInterface(mContent->GetFlattenedTreeParent());
   if (!mSelectControl)
     mGenericTypes &= ~eSelect;
+
+  mStateFlags |= eNoXBLKids;
 }
 
 uint64_t
 XULMenupopupAccessible::NativeState()
 {
   uint64_t state = Accessible::NativeState();
 
 #ifdef DEBUG
--- a/accessible/xul/XULMenuAccessible.h
+++ b/accessible/xul/XULMenuAccessible.h
@@ -25,18 +25,16 @@ public:
 
   // Accessible
   virtual void Description(nsString& aDescription) override;
   virtual a11y::role NativeRole() override;
   virtual uint64_t NativeState() override;
   virtual uint64_t NativeInteractiveState() const override;
   virtual int32_t GetLevelInternal() override;
 
-  virtual bool CanHaveAnonChildren() override;
-
   // ActionAccessible
   virtual uint8_t ActionCount() override;
   virtual void ActionNameAt(uint8_t aIndex, nsAString& aName) override;
   virtual bool DoAction(uint8_t aIndex) override;
   virtual KeyBinding AccessKey() const override;
   virtual KeyBinding KeyboardShortcut() const override;
 
   // Widgets
--- a/accessible/xul/XULSliderAccessible.cpp
+++ b/accessible/xul/XULSliderAccessible.cpp
@@ -18,17 +18,17 @@ using namespace mozilla::a11y;
 ////////////////////////////////////////////////////////////////////////////////
 // XULSliderAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 XULSliderAccessible::
   XULSliderAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   AccessibleWrap(aContent, aDoc)
 {
-  mStateFlags |= eHasNumericValue;
+  mStateFlags |= eHasNumericValue | eNoXBLKids;
 }
 
 // Accessible
 
 role
 XULSliderAccessible::NativeRole()
 {
   return roles::SLIDER;
@@ -122,23 +122,16 @@ bool
 XULSliderAccessible::SetCurValue(double aValue)
 {
   if (AccessibleWrap::SetCurValue(aValue))
     return true;
 
   return SetSliderAttr(nsGkAtoms::curpos, aValue);
 }
 
-bool
-XULSliderAccessible::CanHaveAnonChildren()
-{
-  // Do not allow anonymous xul:slider be accessible.
-  return false;
-}
-
 // Utils
 
 nsIContent*
 XULSliderAccessible::GetSliderElement() const
 {
   if (!mSliderNode) {
     // XXX: we depend on anonymous content.
     mSliderNode = mContent->OwnerDoc()->
--- a/accessible/xul/XULSliderAccessible.h
+++ b/accessible/xul/XULSliderAccessible.h
@@ -21,17 +21,16 @@ class XULSliderAccessible : public Acces
 public:
   XULSliderAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
   virtual void Value(nsString& aValue) override;
   virtual a11y::role NativeRole() override;
   virtual uint64_t NativeInteractiveState() const override;
   virtual bool NativelyUnavailable() const override;
-  virtual bool CanHaveAnonChildren() override;
 
   // Value
   virtual double MaxValue() const override;
   virtual double MinValue() const override;
   virtual double CurValue() const override;
   virtual double Step() const override;
   virtual bool SetCurValue(double aValue) override;
 
--- a/addon-sdk/source/app-extension/bootstrap.js
+++ b/addon-sdk/source/app-extension/bootstrap.js
@@ -21,16 +21,18 @@ const scriptLoader = Cc['@mozilla.org/mo
 const prefService = Cc['@mozilla.org/preferences-service;1'].
                     getService(Ci.nsIPrefService).
                     QueryInterface(Ci.nsIPrefBranch);
 const appInfo = Cc["@mozilla.org/xre/app-info;1"].
                 getService(Ci.nsIXULAppInfo);
 const vc = Cc["@mozilla.org/xpcom/version-comparator;1"].
            getService(Ci.nsIVersionComparator);
 
+const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
+
 const Startup = Cu.import("resource://gre/modules/sdk/system/Startup.js", {}).exports;
 
 
 const REASON = [ 'unknown', 'startup', 'shutdown', 'enable', 'disable',
                  'install', 'uninstall', 'upgrade', 'downgrade' ];
 
 const bind = Function.call.bind(Function.bind);
 
@@ -43,28 +45,22 @@ var resourceDomains = [];
 function setResourceSubstitution(domain, uri) {
   resourceDomains.push(domain);
   resourceHandler.setSubstitution(domain, uri);
 }
 
 // Utility function that synchronously reads local resource from the given
 // `uri` and returns content string.
 function readURI(uri) {
-  let ioservice = Cc['@mozilla.org/network/io-service;1'].
-    getService(Ci.nsIIOService);
+  let channel = NetUtil.newChannel({
+    uri: NetUtil.newURI(uri, 'UTF-8'),
+    loadUsingSystemPrincipal: true
+  });
 
-  let channel = ioservice.newChannel2(uri,
-                                      'UTF-8',
-                                      null,
-                                      null,      // aLoadingNode
-                                      systemPrincipal,
-                                      null,      // aTriggeringPrincipal
-                                      Ci.nsILoadInfo.SEC_NORMAL,
-                                      Ci.nsIContentPolicy.TYPE_OTHER);
-  let stream = channel.open();
+  let stream = channel.open2();
 
   let cstream = Cc['@mozilla.org/intl/converter-input-stream;1'].
     createInstance(Ci.nsIConverterInputStream);
   cstream.init(stream, 'UTF-8', 0, 0);
 
   let str = {};
   let data = '';
   let read = 0;
--- a/addon-sdk/source/lib/sdk/content/page-worker.js
+++ b/addon-sdk/source/lib/sdk/content/page-worker.js
@@ -52,16 +52,17 @@ const ChildPage = Class({
       this.rules = Rules();
       this.rules.add.apply(this.rules, [].concat(options.include));
     }
   },
 
   dispose: function() {
     pages.delete(this.id);
     this.webProgress.removeProgressListener(this);
+    this.webNav.close();
     this.webNav = null;
   },
 
   attachWorker: function() {
     if (!isValidURL(this, this.contentWindow.location.href))
       return;
 
     this.options.id = uuid().toString();
--- a/addon-sdk/source/lib/sdk/content/tab-events.js
+++ b/addon-sdk/source/lib/sdk/content/tab-events.js
@@ -1,42 +1,58 @@
 /* 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/. */
 "use strict";
 
+const { Ci } = require('chrome');
 const system = require('sdk/system/events');
 const { frames } = require('sdk/remote/child');
 const { WorkerChild } = require('sdk/content/worker-child');
 
 // map observer topics to tab event names
 const EVENTS = {
+  'content-document-global-created': 'create',
+  'chrome-document-global-created': 'create',
   'content-document-interactive': 'ready',
   'chrome-document-interactive': 'ready',
   'content-document-loaded': 'load',
   'chrome-document-loaded': 'load',
 // 'content-page-shown': 'pageshow', // bug 1024105
 }
 
 function topicListener({ subject, type }) {
-  let window = subject.defaultView;
-  if (!window)
+  // NOTE detect the window from the subject:
+  // - on *-global-created the subject is the window
+  // - in the other cases it is the document object
+  let window = subject instanceof Ci.nsIDOMWindow ? subject : subject.defaultView;
+  if (!window){
     return;
-  let frame = frames.getFrameForWindow(subject.defaultView);
-  if (frame)
-    frame.port.emit('sdk/tab/event', EVENTS[type]);
+  }
+  let frame = frames.getFrameForWindow(window);
+  if (frame) {
+    let readyState = frame.content.document.readyState;
+    frame.port.emit('sdk/tab/event', EVENTS[type], { readyState });
+  }
 }
 
 for (let topic in EVENTS)
   system.on(topic, topicListener, true);
 
 // bug 1024105 - content-page-shown notification doesn't pass persisted param
 function eventListener({target, type, persisted}) {
   let frame = this;
-  if (target === frame.content.document)
+  if (target === frame.content.document) {
     frame.port.emit('sdk/tab/event', type, persisted);
+  }
 }
 frames.addEventListener('pageshow', eventListener, true);
 
 frames.port.on('sdk/tab/attach', (frame, options) => {
   options.window = frame.content;
   new WorkerChild(options);
 });
+
+// Forward the existent frames's readyState.
+for (let frame of frames) {
+  let readyState = frame.content.document.readyState;
+  frame.port.emit('sdk/tab/event', 'init', { readyState });
+}
--- a/addon-sdk/source/lib/sdk/context-menu.js
+++ b/addon-sdk/source/lib/sdk/context-menu.js
@@ -62,18 +62,19 @@ const OVERFLOW_POPUP_CLASS = "addon-cont
 
 // Holds private properties for API objects
 var internal = ns();
 
 // A little hacky but this is the last process ID that last opened the context
 // menu
 var lastContextProcessId = null;
 
+var uuidModule = require('./util/uuid');
 function uuid() {
-  return require('./util/uuid').uuid().toString();
+  return uuidModule.uuid().toString();
 }
 
 function getScheme(spec) {
   try {
     return URL(spec).scheme;
   }
   catch(e) {
     return null;
--- a/addon-sdk/source/lib/sdk/deprecated/window-utils.js
+++ b/addon-sdk/source/lib/sdk/deprecated/window-utils.js
@@ -5,17 +5,17 @@
 
 module.metadata = {
   'stability': 'deprecated'
 };
 
 const { Cc, Ci } = require('chrome');
 const events = require('../system/events');
 const { getInnerId, getOuterId, windows, isDocumentLoaded, isBrowser,
-        getMostRecentBrowserWindow, getMostRecentWindow } = require('../window/utils');
+        getMostRecentBrowserWindow, getToplevelWindow, getMostRecentWindow } = require('../window/utils');
 const { deprecateFunction } = require('../util/deprecate');
 const { ignoreWindow } = require('sdk/private-browsing/utils');
 const { isPrivateBrowsingSupported } = require('../self');
 
 const windowWatcher = Cc['@mozilla.org/embedcomp/window-watcher;1'].
                        getService(Ci.nsIWindowWatcher);
 const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
                         getService(Ci.nsIAppShellService);
@@ -122,26 +122,26 @@ WindowTracker.prototype = {
       this._unregWindow(window);
   },
 
   handleEvent: function handleEvent(event) {
     try {
       if (event.type == 'load' && event.target) {
         var window = event.target.defaultView;
         if (window)
-          this._regWindow(window);
+          this._regWindow(getToplevelWindow(window));
       }
     }
     catch(e) {
       console.exception(e);
     }
   },
 
   _onToplevelWindowReady: function _onToplevelWindowReady({subject}) {
-    let window = subject;
+    let window = getToplevelWindow(subject);
     // ignore private windows if they are not supported
     if (ignoreWindow(window))
       return;
     this._regWindow(window);
   },
 
   observe: function observe(subject, topic, data) {
     try {
--- a/addon-sdk/source/lib/sdk/io/fs.js
+++ b/addon-sdk/source/lib/sdk/io/fs.js
@@ -116,18 +116,18 @@ function remove(path, recursive) {
   else {
     throw FSError("remove", "ENOENT", 34, path);
   }
 }
 
 /**
  * Utility function to convert either an octal number or string
  * into an octal number
- * 0777 => 0777
- * "0644" => 0644
+ * 0777 => 0o777
+ * "0644" => 0o644
  */
 function Mode(mode, fallback) {
   return isString(mode) ? parseInt(mode, 8) : mode || fallback;
 }
 function Flags(flag) {
   return !isString(flag) ? flag :
          FLAGS[flag] || Error("Unknown file open flag: " + flag);
 }
--- a/addon-sdk/source/lib/sdk/lang/weak-set.js
+++ b/addon-sdk/source/lib/sdk/lang/weak-set.js
@@ -8,26 +8,31 @@ module.metadata = {
 
 "use strict";
 
 const { Cu } = require("chrome");
 
 function makeGetterFor(Type) {
   let cache = new WeakMap();
 
-  return function getFor(target) {
-    if (!cache.has(target))
-      cache.set(target, new Type());
+  return {
+    getFor(target) {
+      if (!cache.has(target))
+        cache.set(target, new Type());
 
-    return cache.get(target);
+      return cache.get(target);
+    },
+    clearFor(target) {
+      return cache.delete(target)
+    }
   }
 }
 
-var getLookupFor = makeGetterFor(WeakMap);
-var getRefsFor = makeGetterFor(Set);
+var {getFor: getLookupFor, clearFor: clearLookupFor} = makeGetterFor(WeakMap);
+var {getFor: getRefsFor, clearFor: clearRefsFor} = makeGetterFor(Set);
 
 function add(target, value) {
   if (has(target, value))
     return;
 
   getLookupFor(target).set(value, true);
   getRefsFor(target).add(Cu.getWeakReference(value));
 }
@@ -39,18 +44,18 @@ function remove(target, value) {
 exports.remove = remove;
 
 function has(target, value) {
   return getLookupFor(target).has(value);
 }
 exports.has = has;
 
 function clear(target) {
-  getLookupFor(target).clear();
-  getRefsFor(target).clear();
+  clearLookupFor(target);
+  clearRefsFor(target);
 }
 exports.clear = clear;
 
 function iterator(target) {
   let refs = getRefsFor(target);
 
   for (let ref of refs) {
     let value = ref.get();
--- a/addon-sdk/source/lib/sdk/loader/cuddlefish.js
+++ b/addon-sdk/source/lib/sdk/loader/cuddlefish.js
@@ -21,17 +21,17 @@ const { classes: Cc, Constructor: CC, in
 // `loadSandbox` is exposed by bootstrap.js
 const loaderURI = module.uri.replace("sdk/loader/cuddlefish.js",
                                      "toolkit/loader.js");
 const xulappURI = module.uri.replace("loader/cuddlefish.js",
                                      "system/xul-app.jsm");
 // We need to keep a reference to the sandbox in order to unload it in
 // bootstrap.js
 
-const loaderSandbox = loadSandbox(loaderURI);
+var loaderSandbox = loadSandbox(loaderURI);
 const loaderModule = loaderSandbox.exports;
 
 const { incompatibility } = Cu.import(xulappURI, {}).XulApp;
 
 const { override, load } = loaderModule;
 
 function CuddlefishLoader(options) {
   let { manifest } = options;
--- a/addon-sdk/source/lib/sdk/net/url.js
+++ b/addon-sdk/source/lib/sdk/net/url.js
@@ -76,17 +76,17 @@ exports.readURI = readURI;
  *  let data = readURISync('resource://gre/modules/NetUtil.jsm');
  */
 function readURISync(uri, charset) {
   charset = typeof charset === "string" ? charset : "UTF-8";
 
   let channel = NetUtil.newChannel({
     uri: NetUtil.newURI(uri, charset),
     loadUsingSystemPrincipal: true});
-  let stream = channel.open();
+  let stream = channel.open2();
 
   let count = stream.available();
   let data = NetUtil.readInputStreamToString(stream, count, { charset : charset });
 
   stream.close();
 
   return data;
 }
--- a/addon-sdk/source/lib/sdk/places/host/host-query.js
+++ b/addon-sdk/source/lib/sdk/places/host/host-query.js
@@ -42,28 +42,42 @@ const MANUAL_QUERY_PROPERTIES = [
 const PLACES_PROPERTIES = [
   'uri', 'title', 'accessCount', 'time'
 ];
 
 function execute (queries, options) {
   return new Promise(resolve => {
     let root = historyService
         .executeQueries(queries, queries.length, options).root;
-    resolve(collect([], root));
+    // Let's extract an eventual uri wildcard, if both domain and uri are set.
+    // See utils.js::urlQueryParser() for more details.
+    // In case of multiple queries, we only retain the first found wildcard.
+    let uriWildcard = queries.reduce((prev, query) => {
+      if (query.uri && query.domain) {
+        if (!prev)
+          prev = query.uri.spec;
+        query.uri = null;
+      }
+      return prev;
+    }, "");
+    resolve(collect([], root, uriWildcard));
   });
 }
 
-function collect (acc, node) {
+function collect (acc, node, uriWildcard) {
   node.containerOpen = true;
   for (let i = 0; i < node.childCount; i++) {
     let child = node.getChild(i);
-    acc.push(child);
+
+    if (!uriWildcard || child.uri.startsWith(uriWildcard)) {
+      acc.push(child);
+    }
     if (child.type === child.RESULT_TYPE_FOLDER) {
       let container = child.QueryInterface(Ci.nsINavHistoryContainerResultNode);
-      collect(acc, container);
+      collect(acc, container, uriWildcard);
     }
   }
   node.containerOpen = false;
   return acc;
 }
 
 function query (queries, options) {
   return new Promise((resolve, reject) => {
--- a/addon-sdk/source/lib/sdk/places/utils.js
+++ b/addon-sdk/source/lib/sdk/places/utils.js
@@ -7,26 +7,28 @@
 module.metadata = {
   "stability": "experimental",
   "engines": {
     "Firefox": "*",
     "SeaMonkey": "*"
   }
 };
 
-const { Cc, Ci } = require('chrome');
+const { Cc, Ci, Cu } = require('chrome');
 const { Class } = require('../core/heritage');
 const { method } = require('../lang/functional');
 const { defer, promised, all } = require('../core/promise');
 const { send } = require('../addon/events');
 const { EventTarget } = require('../event/target');
 const { merge } = require('../util/object');
 const bmsrv = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
                 getService(Ci.nsINavBookmarksService);
 
+Cu.importGlobalProperties(["URL"]);
+
 /*
  * TreeNodes are used to construct dependency trees
  * for BookmarkItems
  */
 var TreeNode = Class({
   initialize: function (value) {
     this.value = value;
     this.children = [];
@@ -123,29 +125,42 @@ exports.isRootGroup = isRootGroup;
 /*
  * Merges appropriate options into query based off of url
  * 4 scenarios:
  *
  * 'moz.com' // domain: moz.com, domainIsHost: true
  *    --> 'http://moz.com', 'http://moz.com/thunderbird'
  * '*.moz.com' // domain: moz.com, domainIsHost: false
  *    --> 'http://moz.com', 'http://moz.com/index', 'http://ff.moz.com/test'
- * 'http://moz.com' // url: http://moz.com/, urlIsPrefix: false
+ * 'http://moz.com' // uri: http://moz.com/
  *    --> 'http://moz.com/'
- * 'http://moz.com/*' // url: http://moz.com/, urlIsPrefix: true
+ * 'http://moz.com/*' // uri: http://moz.com/, domain: moz.com, domainIsHost: true
  *    --> 'http://moz.com/', 'http://moz.com/thunderbird'
  */
 
 function urlQueryParser (query, url) {
   if (!url) return;
   if (/^https?:\/\//.test(url)) {
     query.uri = url.charAt(url.length - 1) === '/' ? url : url + '/';
     if (/\*$/.test(url)) {
-      query.uri = url.replace(/\*$/, '');
-      query.uriIsPrefix = true;
+      // Wildcard searches on URIs are not supported, so try to extract a
+      // domain and filter the data later.
+      url = url.replace(/\*$/, '');
+      try {
+        query.domain = new URL(url).hostname;
+        query.domainIsHost = true;
+        // Unfortunately here we cannot use an expando to store the wildcard,
+        // cause the query is a wrapped native XPCOM object, so we reuse uri.
+        // We clearly don't want to query for both uri and domain, thus we'll
+        // have to handle this in host-query.js::execute()
+        query.uri = url;
+      } catch (ex) {
+        // Cannot extract an host cause it's not a valid uri, the query will
+        // just return nothing.
+      }
     }
   } else {
     if (/^\*/.test(url)) {
       query.domain = url.replace(/^\*\./, '');
       query.domainIsHost = false;
     } else {
       query.domain = url;
       query.domainIsHost = true;
--- a/addon-sdk/source/lib/sdk/preferences/service.js
+++ b/addon-sdk/source/lib/sdk/preferences/service.js
@@ -32,19 +32,16 @@ const Branch = function(branchName) {
     getOwnPropertyDescriptor(target, name, receiver) {
       return {
         configurable: true,
         enumerable: true,
         writable: false,
         value: this.get(target, name, receiver)
       };
     },
-    enumerate(target) {
-      return branchKeys(branchName)[Symbol.iterator]();
-    },
     ownKeys(target) {
       return branchKeys(branchName);
     },
     get(target, name, receiver) {
       return get(`${branchName}${name}`);
     },
     set(target, name, value, receiver) {
       set(`${branchName}${name}`, value);
--- a/addon-sdk/source/lib/sdk/tabs/tab-firefox.js
+++ b/addon-sdk/source/lib/sdk/tabs/tab-firefox.js
@@ -39,16 +39,19 @@ function isDestroyed(tab) {
 }
 
 function isClosed(tab) {
   if (!viewsFor.has(tab))
     return true;
   return viewsFor.get(tab).closing;
 }
 
+// private tab attribute where the remote cached value is stored
+const remoteReadyStateCached = Symbol("remoteReadyStateCached");
+
 const Tab = Class({
   implements: [EventTarget],
   initialize: function(tabElement, options = null) {
     modelsFor.set(tabElement, this);
     viewsFor.set(this, tabElement);
 
     if (options) {
       EventTarget.prototype.initialize.call(this, options);
@@ -120,18 +123,17 @@ const Tab = Class({
     // TODO: Remove the dependency on the windows module, see bug 792670
     require('../windows');
     let tabElement = viewsFor.get(this);
     let domWindow = tabElement.ownerDocument.defaultView;
     return modelFor(domWindow);
   },
 
   get readyState() {
-    // TODO: This will use CPOWs in e10s: bug 1146606
-    return isDestroyed(this) ? undefined : browser(this).contentDocument.readyState;
+    return isDestroyed(this) ? undefined : this[remoteReadyStateCached] || "uninitialized";
   },
 
   pin: function() {
     if (isDestroyed(this))
       return;
 
     pin(viewsFor.get(this));
   },
@@ -301,21 +303,31 @@ function tabEventListener(event, tabElem
       addListItem(window.tabs, tab);
     // The tabs module will