Bug 1249802 - Merge closed branch head into default
authorGregory Szorc <gps@mozilla.com>
Fri, 03 Jun 2016 14:28:48 -0700
changeset 324787 ba31278cd3ba52ebe098e3e957df2ae8fc469d60
parent 324786 09fc62f4a49f6090a64e95beace4d57cb02134c2 (diff)
parent 324604 4dc4cf353e16eb3add81579672791c0574dcae47 (current diff)
child 324788 43961a4e8574c5fe99af75d586568dbf7f00f7d7
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
new file mode 100644
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,189 @@
+# Always ignore node_modules.
+**/node_modules/**/*.*
+
+# Exclude expected objdirs.
+obj*/**
+
+# We ignore all these directories by default, until we get them enabled.
+# If you are enabling a directory, please add directory specific exclusions
+# below.
+accessible/**
+addon-sdk/**
+build/**
+caps/**
+chrome/**
+config/**
+db/**
+docshell/**
+dom/**
+editor/**
+embedding/**
+extensions/**
+gfx/**
+gradle/**
+hal/**
+image/**
+intl/**
+ipc/**
+js/**
+layout/**
+media/**
+memory/**
+mfbt/**
+modules/**
+mozglue/**
+netwerk/**
+nsprpub/**
+other-licenses/**
+parser/**
+probes/**
+python/**
+rdf/**
+startupcache/**
+testing/**
+tools/**
+uriloader/**
+view/**
+webapprt/**
+widget/**
+xpcom/**
+xpfe/**
+xulrunner/**
+
+# b2g exclusions (pref files).
+b2g/app/b2g.js
+b2g/graphene/graphene.js
+b2g/locales/en-US/b2g-l10n.js
+
+# browser/ exclusions
+browser/app/**
+browser/base/content/browser-social.js
+browser/base/content/nsContextMenu.js
+browser/base/content/sanitizeDialog.js
+browser/base/content/test/**
+browser/base/content/newtab/**
+browser/components/downloads/**
+browser/components/feeds/**
+browser/components/preferences/**
+browser/components/privatebrowsing/**
+browser/components/sessionstore/**
+browser/components/shell/**
+browser/components/tabview/**
+browser/components/translation/**
+browser/extensions/pdfjs/**
+browser/extensions/pocket/content/panels/js/vendor/**
+browser/locales/**
+
+# Ignore all of loop since it is imported from github and checked at source.
+browser/extensions/loop/**
+
+# devtools/ exclusions
+devtools/*.js
+devtools/client/canvasdebugger/**
+devtools/client/commandline/**
+devtools/client/debugger/**
+devtools/client/eyedropper/**
+devtools/client/framework/**
+# devtools/client/inspector/shared/*.js files are eslint-clean, so they aren't
+# included in the ignore list.
+devtools/client/inspector/computed/**
+devtools/client/inspector/fonts/**
+devtools/client/inspector/shared/test/**
+devtools/client/inspector/test/**
+devtools/client/inspector/*.js
+devtools/client/jsonview/**
+devtools/client/memory/**
+devtools/client/netmonitor/**
+devtools/client/performance/**
+devtools/client/projecteditor/**
+devtools/client/promisedebugger/**
+devtools/client/responsivedesign/**
+devtools/client/scratchpad/**
+devtools/client/shadereditor/**
+devtools/client/shared/**
+devtools/client/sourceeditor/**
+devtools/client/webaudioeditor/**
+devtools/client/webconsole/**
+devtools/client/webide/**
+devtools/server/**
+devtools/shared/**
+
+# Ignore devtools pre-processed files
+devtools/client/framework/toolbox-process-window.js
+devtools/client/performance/system.js
+devtools/client/webide/webide-prefs.js
+devtools/client/preferences/**
+
+# Ignore devtools third-party libs
+devtools/shared/jsbeautify/*
+devtools/shared/acorn/*
+devtools/client/sourceeditor/tern/*
+devtools/shared/pretty-fast/*
+devtools/shared/sourcemap/*
+devtools/shared/qrcode/decoder/*
+devtools/shared/qrcode/encoder/*
+devtools/client/shared/vendor/*
+devtools/client/shared/d3.js
+devtools/client/webaudioeditor/lib/dagre-d3.js
+devtools/client/sourceeditor/codemirror/*.js
+devtools/client/sourceeditor/codemirror/**/*.js
+devtools/client/sourceeditor/test/codemirror/*
+devtools/client/inspector/markup/test/lib_*
+
+# mobile/android/ exclusions
+mobile/android/chrome/content
+mobile/android/tests/
+
+# Uses `#filter substitution`
+mobile/android/b2gdroid/app/b2gdroid.js
+mobile/android/app/mobile.js
+mobile/android/chrome/content/healthreport-prefs.js
+
+# Uses `#expand`
+mobile/android/chrome/content/about.js
+
+# Not much JS to lint and non-standard at that
+mobile/android/installer/
+mobile/android/locales/
+
+# Pretty sure we're disabling this one anyway
+mobile/android/modules/ContactService.jsm
+
+# Non-standard `(catch ex if ...)`
+mobile/android/components/Snippets.js
+
+# Bug 1178739: Ignore this file as a quick fix for "Illegal yield expression"
+mobile/android/modules/HomeProvider.jsm
+
+# services/ exclusions
+
+# Uses `#filter substitution`
+services/sync/modules/constants.js
+
+# toolkit/ exclusions
+
+# Not part of the default build
+toolkit/components/help/**
+
+# Intentionally invalid JS
+toolkit/components/workerloader/tests/moduleF-syntax-error.js
+
+# Tests old non-star function generators
+toolkit/modules/tests/xpcshell/test_task.js
+
+# Not yet updated
+toolkit/components/osfile/**
+
+# Uses preprocessing
+toolkit/content/widgets/videocontrols.xml
+toolkit/content/widgets/wizard.xml
+toolkit/components/jsdownloads/src/DownloadIntegration.jsm
+toolkit/components/search/nsSearchService.js
+toolkit/components/url-classifier/**
+toolkit/components/urlformatter/nsURLFormatter.js
+toolkit/identity/FirefoxAccounts.jsm
+toolkit/modules/AppConstants.jsm
+toolkit/mozapps/downloads/nsHelperAppDlg.js
+toolkit/mozapps/extensions/internal/AddonConstants.jsm
+toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
+toolkit/webapps/**
new file mode 100644
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +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,70 +4,114 @@
 *~
 *.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
 
 # Build directories
 /obj*/
 
 # Build directories for js shell
-*/_DBG.OBJ/
-*/_OPT.OBJ/
+_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/**/*.so
+python/psutil/**/*.pyd
 python/psutil/build/
 
 # Ignore chrome.manifest files from the devtools loader
-browser/devtools/chrome.manifest
-toolkit/devtools/chrome.manifest
+devtools/client/chrome.manifest
+devtools/shared/chrome.manifest
 
 # Tag files generated by GNU Global
 GTAGS
 GRTAGS
 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/tests/tp5n.zip
+testing/talos/talos/tests/tp5n
+testing/talos/talos/tests/devtools/damp.manifest.develop
--- a/.hgignore
+++ b/.hgignore
@@ -1,28 +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$
+\.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$
 
@@ -31,56 +34,101 @@
 
 # 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
 \.svn/
 
 # Ignore the files and directory that Eclipse IDE creates
 \.project$
 \.cproject$
 \.settings/
 
-# Ignore the directory that JetBrains IDEs create
+# Ignore the files and directory that JetBrains IDEs create.
 \.idea/
+\.iml$
+
+# Gradle cache.
+^.gradle/
+
+# Local Gradle configuration properties.
+^local.properties$
 
 # Python stuff installed at build time.
 ^python/psutil/.*\.so
 ^python/psutil/.*\.pyd
 ^python/psutil/build/
 
 # Git repositories
 .git/
 
 # Ignore chrome.manifest files from the devtools loader
-^browser/devtools/chrome.manifest$
-^toolkit/devtools/chrome.manifest$
+^devtools/client/chrome.manifest$
+^devtools/shared/chrome.manifest$
 
 # git checkout of libstagefright
 ^media/libstagefright/android$
 
 # Tag files generated by GNU Global
 GTAGS
 GRTAGS
 GSYMS
 GPATH
 
-# Unit tests for Loop
+# Various items for Loop
 ^browser/components/loop/standalone/content/config\.js$
-^browser/components/loop/standalone/node_modules/
+^browser/extensions/loop/.*/node_modules/
+^browser/extensions/loop/.*\.module-cache
+^browser/extensions/loop/test/coverage/desktop
+^browser/extensions/loop/test/coverage/shared_standalone
+^browser/extensions/loop/test/visual-regression/diff
+^browser/extensions/loop/test/visual-regression/new
+^browser/extensions/loop/test/visual-regression/refs
 
 # Git clone directory for updating web-platform-tests
 ^testing/web-platform/sync/
 
 # Android Gradle artifacts.
 ^mobile/android/gradle/.gradle
+
+# XCode project cruft
+^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/project.xcworkspace/xcuserdata
+^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/xcuserdata
+
+# Ignore mozharness execution files
+^testing/mozharness/.tox/
+^testing/mozharness/build/
+^testing/mozharness/logs/
+^testing/mozharness/.coverage
+^testing/mozharness/nosetests.xml
+
+# Ignore tox generated dir
+.tox/
+
+# Ignore node_modules from eslint-plugin-mozilla
+^testing/eslint-plugin-mozilla/node_modules/
+
+# Ignore talos virtualenv and tp5n files.
+# The tp5n set is supposed to be decompressed at
+# testing/talos/talos/page_load_test/tp5n in order to run tests like tps
+# locally. Similarly, running talos requires a Python package virtual
+# environment. Both the virtual environment and tp5n files end up littering
+# the status command, so we ignore them.
+^testing/talos/.Python
+^testing/talos/bin/
+^testing/talos/include/
+^testing/talos/lib/
+^testing/talos/talos/tests/tp5n.zip
+^testing/talos/talos/tests/tp5n
+^testing/talos/talos/tests/devtools/damp.manifest.develop
--- a/.hgtags
+++ b/.hgtags
@@ -194,10 +194,90 @@ eead3ccdf2d11feefc12907467cebbe07aa91ea9
 d77cf39268848f8a7e9b38082348b6cd4d1f3b5e FIREFOX_BETA_40_BASE
 0b0822cabbb95d8509852f90c0b7df5da0a4cabc FIREFOX_BETA_39_END
 34e00eb800c52e33059d37f6e41fb255b4bae6b8 FIREFOX_RELEASE_40_BASE
 9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
 312c68b16549de9cea1557f461d5d234bd5e0a7d FIREFOX_AURORA_41_BASE
 9d83ab013ab61c7f6e987bf0e7cbab1a1aed1ca8 FIREFOX_AURORA_40_END
 a019592053c4d93fbbafab8d0bd709529e3746de FIREFOX_BETA_41_BASE
 f147014ff61a12480d377c8bde1f90891772540f FIREFOX_BETA_40_END
-0a913f6cd19b70011d352d46b67869aa9bce6961 FENNEC_41_0b8_RELEASE
-0a913f6cd19b70011d352d46b67869aa9bce6961 FENNEC_41_0b8_BUILD1
+6c0329aacb73ab0510c6f1026ef066dfaed9139c FIREFOX_RELEASE_41_BASE
+9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
+7a19194812eb767bee7cdf8fc36ba9a383c1bead FIREFOX_AURORA_42_BASE
+d561dc208e61b2f2b4e82ab61710e14f56da4ddb FIREFOX_AURORA_41_END
+61bbc30704aa104e9929c719c0fd7957f96f00ea FIREFOX_BETA_42_BASE
+a5bf9cf6777519663e8e1db553727e59d3ad5681 FIREFOX_BETA_41_END
+3f2ff85b2f16c1fd161dc5ba77a5f3f2c52fd127 FIREFOX_RELEASE_42_BASE
+9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
+fcef8ded82219c89298b4e376cfbdfba79a1d35a FIREFOX_AURORA_43_BASE
+b0e20ff87b175424edec414215b325918ccb4792 FIREFOX_AURORA_42_END
+41fdefd640f368bccdeafe6446d42c0a5ad22797 FIREFOX_BETA_43_BASE
+0ec8472a93ac0c7ef0e98ebb91ac780bde12d5a5 FIREFOX_BETA_42_END
+38ffeba26f3e420312e04cb3afb408f4c66a6f2e FIREFOX_RELEASE_43_BASE
+9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
+67a788db9f07822cfef52351bbbe3745dff8bd7f FIREFOX_AURORA_44_BASE
+9d3bc275a924a84ab5f34df58c566af0f87479d0 FIREFOX_AURORA_43_END
+b717b80eec62a7ba9b8842487f157b68c1419edd FIREFOX_BETA_44_BASE
+366dd290472633b06f0942d7737c34e942e0916a FIREFOX_BETA_43_END
+ef3cfadfccb97588653ae06eefdac28ec447c1f6 FIREFOX_RELEASE_44_BASE
+9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
+99137d6d4061f408ae0869122649d8bdf489cc30 FIREFOX_AURORA_45_BASE
+4fbd53613240c431522521b953d5a62692909e65 FIREFOX_AURORA_44_END
+3bfa5bc61b626761d487b45c170b115259f69d6b FIREFOX_BETA_45_BASE
+6a7547e4a0f0e213bb8487c773e16543cbea8c73 FIREFOX_BETA_44_END
+3a9789adadcd0de9ee31b16a89a11985822c6a11 FENNEC_45_0b1_RELEASE
+6c0fd1f666e70f2b11f7083f9e7bf4c844a3716a FENNEC_45_0b1_RELEASE
+3a9789adadcd0de9ee31b16a89a11985822c6a11 FENNEC_45_0b1_BUILD1
+6c0fd1f666e70f2b11f7083f9e7bf4c844a3716a FENNEC_45_0b1_BUILD1
+5e1da6523e97d7f8b01004bbe33118ac784b40ea FIREFOX_45_0b1_RELEASE
+6c0fd1f666e70f2b11f7083f9e7bf4c844a3716a FIREFOX_45_0b1_RELEASE
+5e1da6523e97d7f8b01004bbe33118ac784b40ea FIREFOX_45_0b1_BUILD1
+6c0fd1f666e70f2b11f7083f9e7bf4c844a3716a FIREFOX_45_0b1_BUILD1
+bbe048ab30ad3321a6505697703e5fee20e91343 FIREFOX_RELEASE_45_BASE
+9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
+67c66c2878aed17ae3096d7db483ddbb2293c503 FIREFOX_AURORA_46_BASE
+d82221ba4219e4ac04ecfe2a5301703411e176fa FIREFOX_AURORA_45_END
+89effb961712d4a5f84e90bcdd4e421ed6645eea FIREFOX_BETA_46_BASE
+78fe98c670fcc9a1548ac655ae9a488d940fd9c8 FIREFOX_BETA_45_END
+fb3494d06dfb73e26df72ca7a4bc4ef5ebf8795c FIREFOX_46_0b1_RELEASE
+5904e3eb711dd263a6d2deb63b14e0c44e577054 FIREFOX_46_0b2_BUILD3
+5904e3eb711dd263a6d2deb63b14e0c44e577054 FIREFOX_46_0b2_RELEASE
+2f6f69a19150e03ad68062f2ac92342afb1ef787 FIREFOX_46_0b4_BUILD2
+2f6f69a19150e03ad68062f2ac92342afb1ef787 FIREFOX_46_0b4_RELEASE
+53d6e6648f97402a740687a82a297c66f5396548 FIREFOX_46_0b5_BUILD2
+53d6e6648f97402a740687a82a297c66f5396548 FIREFOX_46_0b5_RELEASE
+97b81104ac035d6a8f6ed59a1aad63fcc23e73c8 FIREFOX_46_0b6_BUILD1
+97b81104ac035d6a8f6ed59a1aad63fcc23e73c8 FIREFOX_46_0b6_RELEASE
+191f5eb4cbd72590277296cdb90d355adb347d45 FIREFOX_46_0b7_BUILD2
+191f5eb4cbd72590277296cdb90d355adb347d45 FIREFOX_46_0b7_RELEASE
+0334bcac4033f4f163476677165acd406e08fed8 FIREFOX_46_0b8_BUILD1
+0334bcac4033f4f163476677165acd406e08fed8 FIREFOX_46_0b8_RELEASE
+b007110e90053e58946b59765605bfca766c30d1 FIREFOX_46_0b9_BUILD1
+b007110e90053e58946b59765605bfca766c30d1 FIREFOX_46_0b9_RELEASE
+9ea83990839bd513869018e57bcbedb3454b63bb FIREFOX_46_0b10_BUILD1
+9ea83990839bd513869018e57bcbedb3454b63bb FIREFOX_46_0b10_RELEASE
+6c4646c7a6d6506e744c92a8170310191904c98e FIREFOX_RELEASE_46_BASE
+076bf6a0ac85ec6a4f3ee7c3efe653964d92b9f2 FIREFOX_46_0b11_BUILD1
+076bf6a0ac85ec6a4f3ee7c3efe653964d92b9f2 FIREFOX_46_0b11_RELEASE
+9f12a9fab080f2d363d7424e25b9ffe85ebc3414 FIREFOX_AURORA_28_BASE
+68d3781deda0d4d58ec9877862830db89669b3a5 FIREFOX_AURORA_47_BASE
+43d92f7052e7bab870c9b994d4b0a0f42d26b7a7 FIREFOX_AURORA_46_END
+8551b253f4061db31e4be7829c2f70c2610caf42 FIREFOX_BETA_47_BASE
+a2290938ee6cf794896a9347980bcb00ebb24c68 FIREFOX_BETA_46_END
+5bbf2e7c2fc6ff9010b1948e2f11477f48ee36e2 FIREFOX_47_0b1_BUILD2
+5bbf2e7c2fc6ff9010b1948e2f11477f48ee36e2 FIREFOX_47_0b1_RELEASE
+6f82d30fe05e1412e744cb76af86f0c9ffe509d4 FIREFOX_47_0b2_BUILD1
+6f82d30fe05e1412e744cb76af86f0c9ffe509d4 FIREFOX_47_0b2_RELEASE
+609000bcc11211d7c27ceea36fa2d2262fa0523f FIREFOX_47_0b3_BUILD1
+609000bcc11211d7c27ceea36fa2d2262fa0523f FIREFOX_47_0b3_RELEASE
+2991f214d4f4d8a3c5cfd95e6223f0660006767d FIREFOX_47_0b4_BUILD1
+2991f214d4f4d8a3c5cfd95e6223f0660006767d FIREFOX_47_0b4_RELEASE
+93a53170dedffdff45bf9eb8dac6e5ef7a13c4ba FIREFOX_47_0b5_BUILD1
+93a53170dedffdff45bf9eb8dac6e5ef7a13c4ba FIREFOX_47_0b5_RELEASE
+7d1f3450acc47025876964c1eca854ae027934f3 FIREFOX_47_0b6_BUILD1
+7d1f3450acc47025876964c1eca854ae027934f3 FIREFOX_47_0b6_RELEASE
+0723a0212f5e0b30d7532d4e35eba7759fb54507 FIREFOX_47_0b7_BUILD1
+0723a0212f5e0b30d7532d4e35eba7759fb54507 FIREFOX_47_0b7_RELEASE
+cb27eacbe04abc5f91a0379c23617715aab432ec FIREFOX_47_0b8_BUILD1
+cb27eacbe04abc5f91a0379c23617715aab432ec FIREFOX_47_0b8_RELEASE
+2ee4473c729acb2ba7dc723e7affe79ce14bff85 FIREFOX_47_0b9_BUILD1
+2ee4473c729acb2ba7dc723e7affe79ce14bff85 FIREFOX_47_0b9_RELEASE
+cf6ec12bd62001b93387ffb184a8841644255b5e FIREFOX_RELEASE_47_BASE
--- a/AUTHORS
+++ b/AUTHORS
@@ -354,16 +354,17 @@ Fernando Jimenez <ferjmoreno@gmail.com>
 Flock Inc.
 Florian Boesch <pyalot@gmail.com>
 Florian Hänel <heeen@gmx.de>
 Florian Queze <florian@queze.net>
 Florian Scholz <elchi3@elchi3.de>
 <flying@dom.natm.ru>
 France Telecom Research and Development
 Franck
+Francois Marier <francois@fmarier.org>
 Frank Tang <ftang@netscape.com>
 Frank Yan <fyan@mozilla.com>
 Franky Braem
 <franky@pacificconnections.com>
 Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
 Frederic Plourde <frederic.plourde@polymtl.ca>
 Frederic Wang <fred.wang@free.fr>
 Fredrik Holmqvist <thesuckiestemail@yahoo.se>
--- 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,41 +10,49 @@ 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
-ifndef LIBXUL_SDK
 ifdef COMPILE_ENVIRONMENT
 $(TIERS) binaries:: $(topsrcdir)/js/src/configure js/src/config.status
 endif
 endif
 endif
 endif
 
 ifdef JS_STANDALONE
@@ -53,92 +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.
 
-backend.RecursiveMakeBackend:
+ifndef TEST_MOZBUILD
+
+.PHONY: backend
+backend: $(BUILD_BACKEND_FILES)
+
+# A traditional rule would look like this:
+#    backend.%:
+#        @echo do stuff
+#
+# But with -j<n>, and multiple items in BUILD_BACKEND_FILES, the command would
+# run multiple times in parallel.
+#
+# "Fortunately", make has some weird semantics for pattern rules: if there are
+# multiple targets in a pattern rule and each of them is matched at most once,
+# the command will only run once. So:
+#     backend%RecursiveMakeBackend backend%FasterMakeBackend:
+#         @echo do stuff
+#     backend: backend.RecursiveMakeBackend backend.FasterMakeBackend
+# would only execute the command once.
+#
+# Credit where due: http://stackoverflow.com/questions/2973445/gnu-makefile-rule-generating-a-few-targets-from-a-single-source-file/3077254#3077254
+$(subst .,%,$(BUILD_BACKEND_FILES)):
 	@echo 'Build configuration changed. Regenerating backend.'
 	$(PYTHON) config.status
 
-Makefile: backend.RecursiveMakeBackend
+Makefile: $(BUILD_BACKEND_FILES)
 	@$(TOUCH) $@
 
-include backend.RecursiveMakeBackend.pp
+define build_backend_rule
+$(1)_files := $$(shell cat $(1).in)
+$(1): $$($(1)_files)
+$$($(1)_files):
 
-default:: backend.RecursiveMakeBackend
+endef
+$(foreach file,$(BUILD_BACKEND_FILES),$(eval $(call build_backend_rule,$(file))))
+
+default:: $(BUILD_BACKEND_FILES)
+endif
 
 install_manifests := \
-  $(addprefix dist/,bin branding idl include public private sdk xpi-stage) \
+  $(addprefix dist/,branding idl include public private sdk xpi-stage) \
   _tests \
   $(NULL)
+# Skip the dist/bin install manifest when using the hybrid
+# FasterMake/RecursiveMake backend. This is a hack until bug 1241744 moves
+# xpidl handling to FasterMake in that case, mechanically making the dist/bin
+# install manifest non-existent (non-existent manifests being skipped)
+ifeq (,$(filter FasterMake+RecursiveMake,$(BUILD_BACKENDS)))
+install_manifests += dist/bin
+endif
 install_manifest_depends = \
   CLOBBER \
   $(configure_dir)/configure \
   config.status \
-  backend.RecursiveMakeBackend \
+  $(BUILD_BACKEND_FILES) \
   $(NULL)
 
 ifndef JS_STANDALONE
-ifndef LIBXUL_SDK
 ifdef COMPILE_ENVIRONMENT
 install_manifest_depends += \
   $(topsrcdir)/js/src/configure \
   js/src/config.status \
   $(NULL)
 endif
 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 /,_,$*)))
 
-install-_tests: $(install_manifest_depends)
-	$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )_tests _build_manifests/install/tests)
+# Dummy wrapper rule to allow the faster backend to piggy back
+$(addprefix install-,$(subst /,_,$(filter dist/%,$(install_manifests)))): install-dist_%: install-dist/% ;
 
 # For compatibility
 .PHONY: install-tests
 install-tests: install-_tests
 
 include $(topsrcdir)/build/moz-automation.mk
 
 # dist and _tests should be purged during cleaning. However, we don't want them
@@ -150,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
 
@@ -210,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
@@ -255,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/README.txt
+++ b/README.txt
@@ -17,11 +17,11 @@ If you have a question about developing 
 on http://developer.mozilla.org, you can try asking your question in a
 mozilla.* Usenet group, or on IRC at irc.mozilla.org. [The Mozilla news groups
 are accessible on Google Groups, or news.mozilla.org with a NNTP reader.]
 
 You can download nightly development builds from the Mozilla FTP server.
 Keep in mind that nightly builds, which are used by Mozilla developers for
 testing, may be buggy. Firefox nightlies, for example, can be found at:
 
-    ftp://ftp.mozilla.org/pub/firefox/nightly/latest-trunk/
+    https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/
             - or -
     http://nightly.mozilla.org/
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -9,16 +9,18 @@
 #include "Accessible-inl.h"
 #include "ApplicationAccessibleWrap.h"
 #include "InterfaceInitFuncs.h"
 #include "nsAccUtils.h"
 #include "mozilla/a11y/PDocAccessible.h"
 #include "OuterDocAccessible.h"
 #include "ProxyAccessible.h"
 #include "RootAccessible.h"
+#include "TableAccessible.h"
+#include "TableCellAccessible.h"
 #include "nsMai.h"
 #include "nsMaiHyperlink.h"
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "prprf.h"
 #include "nsStateMap.h"
 #include "mozilla/a11y/Platform.h"
 #include "Relation.h"
@@ -29,17 +31,17 @@
 #include "mozilla/ArrayUtils.h"
 #include "nsXPCOMStrings.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIPersistentProperties2.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
-AccessibleWrap::EAvailableAtkSignals AccessibleWrap::gAvailableAtkSignals =
+MaiAtkObject::EAvailableAtkSignals MaiAtkObject::gAvailableAtkSignals =
   eUnknown;
 
 //defined in ApplicationAccessibleWrap.cpp
 extern "C" GType g_atk_hyperlink_impl_type;
 
 /* MaiAtkObject */
 
 enum {
@@ -138,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);
   }
 }
 
@@ -552,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*
@@ -590,17 +592,18 @@ getNameCB(AtkObject* aAtkObj)
 
   return aAtkObj->name;
 }
 
 static void
 MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName)
 {
   NS_ConvertUTF16toUTF8 newNameUTF8(aNewName);
-  if (aAtkObj->name && newNameUTF8.Equals(aAtkObj->name))
+  if (aAtkObj->name &&
+      !strncmp(aAtkObj->name, newNameUTF8.get(), newNameUTF8.Length()))
     return;
 
   // Below we duplicate the functionality of atk_object_set_name(),
   // but without calling atk_object_get_name(). Instead of
   // atk_object_get_name() we directly access aAtkObj->name. This is because
   // atk_object_get_name() would call getNameCB() which would call
   // MaybeFireNameChange() (or atk_object_set_name() before this problem was
   // fixed) and we would get an infinite recursion.
@@ -642,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))
@@ -756,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());
@@ -817,22 +815,38 @@ getParentCB(AtkObject *aAtkObj)
     atk_object_set_parent(aAtkObj, atkParent);
 
   return aAtkObj->accessible_parent;
 }
 
 gint
 getChildCountCB(AtkObject *aAtkObj)
 {
-    AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
-    if (!accWrap || nsAccUtils::MustPrune(accWrap)) {
-        return 0;
+  if (AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj)) {
+    if (nsAccUtils::MustPrune(accWrap)) {
+      return 0;
+    }
+
+    uint32_t count = accWrap->EmbeddedChildCount();
+    if (count) {
+      return static_cast<gint>(count);
     }
 
-    return static_cast<gint>(accWrap->EmbeddedChildCount());
+    OuterDocAccessible* outerDoc = accWrap->AsOuterDoc();
+    if (outerDoc && outerDoc->RemoteChildDoc()) {
+      return 1;
+    }
+  }
+
+  ProxyAccessible* proxy = GetProxy(aAtkObj);
+  if (proxy && !proxy->MustPruneChildren()) {
+    return proxy->EmbeddedChildCount();
+  }
+
+  return 0;
 }
 
 AtkObject *
 refChildCB(AtkObject *aAtkObj, gint aChildIndex)
 {
   // aChildIndex should not be less than zero
   if (aChildIndex < 0) {
     return nullptr;
@@ -962,16 +976,23 @@ UpdateAtkRelation(RelationType aType, Ac
     atk_relation_set_remove(aAtkSet, atkRelation);
 
   Relation rel(aAcc->RelationByType(aType));
   nsTArray<AtkObject*> targets;
   Accessible* tempAcc = nullptr;
   while ((tempAcc = rel.Next()))
     targets.AppendElement(AccessibleWrap::GetAtkObject(tempAcc));
 
+  if (aType == RelationType::EMBEDS && aAcc->IsRoot()) {
+    if (ProxyAccessible* proxyDoc =
+        aAcc->AsRoot()->GetPrimaryRemoteTopLevelContentDoc()) {
+      targets.AppendElement(GetWrapperFor(proxyDoc));
+    }
+  }
+
   if (targets.Length()) {
     atkRelation = atk_relation_new(targets.Elements(),
                                    targets.Length(), aAtkType);
     atk_relation_set_add(aAtkSet, atkRelation);
     g_object_unref(atkRelation);
   }
 }
 
@@ -993,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);
@@ -1029,24 +1050,27 @@ refRelationSetCB(AtkObject *aAtkObj)
   return relation_set;
 }
 
 // Check if aAtkObj is a valid MaiAtkObject, and return the AccessibleWrap
 // for it.
 AccessibleWrap*
 GetAccessibleWrap(AtkObject* aAtkObj)
 {
-  NS_ENSURE_TRUE(IS_MAI_OBJECT(aAtkObj), nullptr);
+  bool isMAIObject = IS_MAI_OBJECT(aAtkObj);
+  NS_ENSURE_TRUE(isMAIObject || MAI_IS_ATK_SOCKET(aAtkObj),
+                 nullptr);
 
-  // Make sure its native is an AccessibleWrap not a proxy.
-  if (MAI_ATK_OBJECT(aAtkObj)->accWrap & IS_PROXY)
-    return nullptr;
-
-    AccessibleWrap* accWrap =
-      reinterpret_cast<AccessibleWrap*>(MAI_ATK_OBJECT(aAtkObj)->accWrap);
+  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();
@@ -1054,21 +1078,26 @@ GetAccessibleWrap(AtkObject* aAtkObj)
     return nullptr;
 
   return accWrap;
 }
 
 ProxyAccessible*
 GetProxy(AtkObject* aObj)
 {
-  if (!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);
 }
 
@@ -1076,29 +1105,37 @@ static uint16_t
 GetInterfacesForProxy(ProxyAccessible* aProxy, uint32_t aInterfaces)
 {
   uint16_t interfaces = 1 << MAI_INTERFACE_COMPONENT;
   if (aInterfaces & Interfaces::HYPERTEXT)
     interfaces |= (1 << MAI_INTERFACE_HYPERTEXT) | (1 << MAI_INTERFACE_TEXT)
         | (1 << MAI_INTERFACE_EDITABLE_TEXT);
 
   if (aInterfaces & Interfaces::HYPERLINK)
-    interfaces |= MAI_INTERFACE_HYPERLINK_IMPL;
+    interfaces |= 1 << MAI_INTERFACE_HYPERLINK_IMPL;
 
   if (aInterfaces & Interfaces::VALUE)
-    interfaces |= MAI_INTERFACE_VALUE;
+    interfaces |= 1 << MAI_INTERFACE_VALUE;
 
   if (aInterfaces & Interfaces::TABLE)
-    interfaces |= MAI_INTERFACE_TABLE;
+    interfaces |= 1 << MAI_INTERFACE_TABLE;
 
   if (aInterfaces & Interfaces::IMAGE)
-    interfaces |= MAI_INTERFACE_IMAGE;
+    interfaces |= 1 << MAI_INTERFACE_IMAGE;
 
   if (aInterfaces & Interfaces::DOCUMENT)
-    interfaces |= MAI_INTERFACE_DOCUMENT;
+    interfaces |= 1 << MAI_INTERFACE_DOCUMENT;
+
+  if (aInterfaces & Interfaces::SELECTION) {
+    interfaces |= 1 << MAI_INTERFACE_SELECTION;
+  }
+
+  if (aInterfaces & Interfaces::ACTION) {
+    interfaces |= 1 << MAI_INTERFACE_ACTION;
+  }
 
   return interfaces;
 }
 
 void
 a11y::ProxyCreated(ProxyAccessible* aProxy, uint32_t aInterfaces)
 {
   GType type = GetMaiAtkType(GetInterfacesForProxy(aProxy, aInterfaces));
@@ -1127,16 +1164,20 @@ a11y::ProxyDestroyed(ProxyAccessible* aP
 }
 
 nsresult
 AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
 {
   nsresult rv = Accessible::HandleAccEvent(aEvent);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  if (IPCAccessibilityActive()) {
+    return NS_OK;
+  }
+
     Accessible* accessible = aEvent->GetAccessible();
     NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
 
     // The accessible can become defunct if we have an xpcom event listener
     // which decides it would be fun to change the DOM and flush layout.
     if (accessible->IsDefunct())
         return NS_OK;
 
@@ -1164,17 +1205,28 @@ AccessibleWrap::HandleAccEvent(AccEvent*
         AccStateChangeEvent* event = downcast_accEvent(aEvent);
         MAI_ATK_OBJECT(atkObj)->FireStateChangeEvent(event->GetState(),
                                                      event->IsStateEnabled());
         break;
       }
 
     case nsIAccessibleEvent::EVENT_TEXT_REMOVED:
     case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
-        return FireAtkTextChangedEvent(aEvent, atkObj);
+      {
+        AccTextChangeEvent* event = downcast_accEvent(aEvent);
+        NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
+
+        MAI_ATK_OBJECT(atkObj)-> FireTextChangeEvent(event->ModifiedText(),
+                                                     event->GetStartOffset(),
+                                                     event->GetLength(),
+                                                     event->IsTextInserted(),
+                                                     event->IsFromUserInput());
+
+        return NS_OK;
+      }
 
     case nsIAccessibleEvent::EVENT_FOCUS:
       {
         a11y::RootAccessible* rootAccWrap = accWrap->RootAccessible();
         if (rootAccWrap && rootAccWrap->mActivated) {
             atk_focus_tracker_notify(atkObj);
             // Fire state change event for focus
             atk_object_notify_state_change(atkObj, ATK_STATE_FOCUSED, true);
@@ -1188,16 +1240,17 @@ AccessibleWrap::HandleAccEvent(AccEvent*
         accessible->Name(newName);
 
         MaybeFireNameChange(atkObj, newName);
 
         break;
       }
 
   case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
+  case nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE:
     if (accessible->HasNumericValue()) {
       // Make sure this is a numeric value. Don't fire for string value changes
       // (e.g. text editing) ATK values are always numeric.
       g_object_notify((GObject*)atkObj, "accessible-value");
     }
     break;
 
     case nsIAccessibleEvent::EVENT_SELECTION:
@@ -1212,16 +1265,21 @@ AccessibleWrap::HandleAccEvent(AccEvent*
     }
 
     case nsIAccessibleEvent::EVENT_SELECTION_WITHIN:
     {
       g_signal_emit_by_name(atkObj, "selection_changed");
       break;
     }
 
+    case nsIAccessibleEvent::EVENT_ALERT:
+      // A hack using state change showing events as alert events.
+      atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, true);
+      break;
+
     case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
         g_signal_emit_by_name(atkObj, "text_selection_changed");
         break;
 
     case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED:
       {
         AccCaretMoveEvent* caretMoveEvent = downcast_accEvent(aEvent);
         NS_ASSERTION(caretMoveEvent, "Event needs event data");
@@ -1409,16 +1467,23 @@ a11y::ProxyEvent(ProxyAccessible* aTarge
     atk_focus_tracker_notify(wrapper); // fire extra focus event
     atk_object_notify_state_change(wrapper, ATK_STATE_VISIBLE, true);
     atk_object_notify_state_change(wrapper, ATK_STATE_SHOWING, true);
     break;
   case nsIAccessibleEvent::EVENT_MENUPOPUP_END:
     atk_object_notify_state_change(wrapper, ATK_STATE_VISIBLE, false);
     atk_object_notify_state_change(wrapper, ATK_STATE_SHOWING, false);
     break;
+  case nsIAccessibleEvent::EVENT_ALERT:
+    // A hack using state change showing events as alert events.
+    atk_object_notify_state_change(wrapper, ATK_STATE_SHOWING, true);
+    break;
+  case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
+    g_object_notify((GObject*)wrapper, "accessible-value");
+    break;
   }
 }
 
 void
 a11y::ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t aState,
                             bool aEnabled)
 {
   MaiAtkObject* atkObj = MAI_ATK_OBJECT(GetWrapperFor(aTarget));
@@ -1450,65 +1515,63 @@ MaiAtkObject::FireStateChangeEvent(uint6
             // Fire state change for first state if there is one to map
             atk_object_notify_state_change(&parent,
                                            gAtkStateMap[stateIndex].atkState,
                                            aEnabled);
         }
     }
 }
 
+void
+a11y::ProxyTextChangeEvent(ProxyAccessible* aTarget, const nsString& aStr,
+                           int32_t aStart, uint32_t aLen, bool aIsInsert,
+                           bool aFromUser)
+{
+  MaiAtkObject* atkObj = MAI_ATK_OBJECT(GetWrapperFor(aTarget));
+  atkObj->FireTextChangeEvent(aStr, aStart, aLen, aIsInsert, aFromUser);
+}
+
 #define OLD_TEXT_INSERTED "text_changed::insert"
 #define OLD_TEXT_REMOVED "text_changed::delete"
 static const char* oldTextChangeStrings[2][2] = {
   { OLD_TEXT_REMOVED NON_USER_EVENT, OLD_TEXT_INSERTED NON_USER_EVENT },
   { OLD_TEXT_REMOVED, OLD_TEXT_INSERTED }
 };
 
 #define TEXT_INSERTED "text-insert"
 #define TEXT_REMOVED "text-remove"
 #define NON_USER_DETAIL "::system"
 static const char* textChangedStrings[2][2] = {
   { TEXT_REMOVED NON_USER_DETAIL, TEXT_INSERTED NON_USER_DETAIL },
   { TEXT_REMOVED, TEXT_INSERTED}
 };
 
-nsresult
-AccessibleWrap::FireAtkTextChangedEvent(AccEvent* aEvent,
-                                        AtkObject* aObject)
+void
+MaiAtkObject::FireTextChangeEvent(const nsString& aStr, int32_t aStart,
+                                  uint32_t aLen, bool aIsInsert,
+                                  bool aFromUser)
 {
-    AccTextChangeEvent* event = downcast_accEvent(aEvent);
-    NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
-
-    int32_t start = event->GetStartOffset();
-    uint32_t length = event->GetLength();
-    bool isInserted = event->IsTextInserted();
-    bool isFromUserInput = aEvent->IsFromUserInput();
-
   if (gAvailableAtkSignals == eUnknown)
     gAvailableAtkSignals =
-      g_signal_lookup("text-insert", G_OBJECT_TYPE(aObject)) ?
+      g_signal_lookup("text-insert", G_OBJECT_TYPE(this)) ?
         eHaveNewAtkTextSignals : eNoNewAtkSignals;
 
   if (gAvailableAtkSignals == eNoNewAtkSignals) {
     // XXX remove this code and the gHaveNewTextSignals check when we can
     // stop supporting old atk since it doesn't really work anyway
     // see bug 619002
     const char* signal_name =
-      oldTextChangeStrings[isFromUserInput][isInserted];
-    g_signal_emit_by_name(aObject, signal_name, start, length);
+      oldTextChangeStrings[aFromUser][aIsInsert];
+    g_signal_emit_by_name(this, signal_name, aStart, aLen);
   } else {
-    nsAutoString text;
-    event->GetModifiedText(text);
     const char* signal_name =
-      textChangedStrings[isFromUserInput][isInserted];
-    g_signal_emit_by_name(aObject, signal_name, start, length,
-                          NS_ConvertUTF16toUTF8(text).get());
+      textChangedStrings[aFromUser][aIsInsert];
+    g_signal_emit_by_name(this, signal_name, aStart, aLen,
+                          NS_ConvertUTF16toUTF8(aStr).get());
   }
-
-  return NS_OK;
 }
 
 #define ADD_EVENT "children_changed::add"
 #define HIDE_EVENT "children_changed::remove"
 
 static const char *kMutationStrings[2][2] = {
   { HIDE_EVENT NON_USER_EVENT, ADD_EVENT NON_USER_EVENT },
   { HIDE_EVENT, ADD_EVENT },
@@ -1523,8 +1586,123 @@ AccessibleWrap::FireAtkShowHideEvent(Acc
     NS_ENSURE_STATE(parentObject);
 
     bool isFromUserInput = aEvent->IsFromUserInput();
     const char *signal_name = kMutationStrings[isFromUserInput][aIsAdded];
     g_signal_emit_by_name(parentObject, signal_name, indexInParent, aObject, nullptr);
 
     return NS_OK;
 }
+
+// static
+void
+AccessibleWrap::GetKeyBinding(Accessible* aAccessible, nsAString& aResult)
+{
+  // Return all key bindings including access key and keyboard shortcut.
+
+  // Get access key.
+  nsAutoString keyBindingsStr;
+  KeyBinding keyBinding = aAccessible->AccessKey();
+  if (!keyBinding.IsEmpty()) {
+    keyBinding.AppendToString(keyBindingsStr, KeyBinding::eAtkFormat);
+
+    Accessible* parent = aAccessible->Parent();
+    roles::Role role = parent ? parent->Role() : roles::NOTHING;
+    if (role == roles::PARENT_MENUITEM || role == roles::MENUITEM ||
+        role == roles::RADIO_MENU_ITEM || role == roles::CHECK_MENU_ITEM) {
+      // It is submenu, expose keyboard shortcuts from menu hierarchy like
+      // "s;<Alt>f:s"
+      nsAutoString keysInHierarchyStr = keyBindingsStr;
+      do {
+        KeyBinding parentKeyBinding = parent->AccessKey();
+        if (!parentKeyBinding.IsEmpty()) {
+          nsAutoString str;
+          parentKeyBinding.ToString(str, KeyBinding::eAtkFormat);
+          str.Append(':');
+
+          keysInHierarchyStr.Insert(str, 0);
+        }
+      } while ((parent = parent->Parent()) && parent->Role() != roles::MENUBAR);
+
+      keyBindingsStr.Append(';');
+      keyBindingsStr.Append(keysInHierarchyStr);
+    }
+  } else {
+    // No access key, add ';' to point this.
+    keyBindingsStr.Append(';');
+  }
+
+  // Get keyboard shortcut.
+  keyBindingsStr.Append(';');
+  keyBinding = aAccessible->KeyboardShortcut();
+  if (!keyBinding.IsEmpty()) {
+    keyBinding.AppendToString(keyBindingsStr, KeyBinding::eAtkFormat);
+  }
+  aResult = keyBindingsStr;
+}
+
+// static
+Accessible*
+AccessibleWrap::GetColumnHeader(TableAccessible* aAccessible, int32_t aColIdx)
+{
+  if (!aAccessible) {
+    return nullptr;
+  }
+
+  Accessible* cell = aAccessible->CellAt(0, aColIdx);
+  if (!cell) {
+    return nullptr;
+  }
+
+  // If the cell at the first row is column header then assume it is column
+  // header for all rows,
+  if (cell->Role() == roles::COLUMNHEADER) {
+    return cell;
+  }
+
+  // otherwise get column header for the data cell at the first row.
+  TableCellAccessible* tableCell = cell->AsTableCell();
+  if (!tableCell) {
+    return nullptr;
+  }
+
+  AutoTArray<Accessible*, 10> headerCells;
+  tableCell->ColHeaderCells(&headerCells);
+  if (headerCells.IsEmpty()) {
+    return nullptr;
+  }
+
+  return headerCells[0];
+}
+
+// static
+Accessible*
+AccessibleWrap::GetRowHeader(TableAccessible* aAccessible, int32_t aRowIdx)
+{
+  if (!aAccessible) {
+    return nullptr;
+  }
+
+  Accessible* cell = aAccessible->CellAt(aRowIdx, 0);
+  if (!cell) {
+    return nullptr;
+  }
+
+  // If the cell at the first column is row header then assume it is row
+  // header for all columns,
+  if (cell->Role() == roles::ROWHEADER) {
+    return cell;
+  }
+
+  // otherwise get row header for the data cell at the first column.
+  TableCellAccessible* tableCell = cell->AsTableCell();
+  if (!tableCell) {
+    return nullptr;
+  }
+
+  AutoTArray<Accessible*, 10> headerCells;
+  tableCell->RowHeaderCells(&headerCells);
+  if (headerCells.IsEmpty()) {
+    return nullptr;
+  }
+
+  return headerCells[0];
+}
--- a/accessible/atk/AccessibleWrap.h
+++ b/accessible/atk/AccessibleWrap.h
@@ -64,39 +64,31 @@ public:
   bool IsValidObject();
 
   static const char * ReturnString(nsAString &aString) {
     static nsCString returnedString;
     returnedString = NS_ConvertUTF16toUTF8(aString);
     return returnedString.get();
   }
 
+  static void GetKeyBinding(Accessible* aAccessible, nsAString& aResult);
+
+  static Accessible* GetColumnHeader(TableAccessible* aAccessible,
+                                     int32_t aColIdx);
+  static Accessible* GetRowHeader(TableAccessible* aAccessible,
+                                  int32_t aRowIdx);
 protected:
 
   nsresult FireAtkStateChangeEvent(AccEvent* aEvent, AtkObject *aObject);
   nsresult FireAtkTextChangedEvent(AccEvent* aEvent, AtkObject *aObject);
   nsresult FireAtkShowHideEvent(AccEvent* aEvent, AtkObject *aObject,
                                 bool aIsAdded);
 
   AtkObject *mAtkObject;
 
 private:
-
-  /*
-   * do we have text-remove and text-insert signals if not we need to use
-   * text-changed see AccessibleWrap::FireAtkTextChangedEvent() and
-   * bug 619002
-   */
-  enum EAvailableAtkSignals {
-    eUnknown,
-    eHaveNewAtkTextSignals,
-    eNoNewAtkSignals
-  };
-
-  static EAvailableAtkSignals gAvailableAtkSignals;
-
   uint16_t CreateMaiInterfaces();
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif /* __NS_ACCESSIBLE_WRAP_H__ */
--- a/accessible/atk/AtkSocketAccessible.cpp
+++ b/accessible/atk/AtkSocketAccessible.cpp
@@ -16,45 +16,16 @@ using namespace mozilla::a11y;
 AtkSocketEmbedType AtkSocketAccessible::g_atk_socket_embed = nullptr;
 GType AtkSocketAccessible::g_atk_socket_type = G_TYPE_INVALID;
 const char* AtkSocketAccessible::sATKSocketEmbedSymbol = "atk_socket_embed";
 const char* AtkSocketAccessible::sATKSocketGetTypeSymbol = "atk_socket_get_type";
 
 bool AtkSocketAccessible::gCanEmbed = FALSE;
 
 extern "C" void mai_atk_component_iface_init(AtkComponentIface* aIface);
-extern "C" GType mai_atk_socket_get_type(void);
-
-/* MaiAtkSocket */
-
-#define MAI_TYPE_ATK_SOCKET              (mai_atk_socket_get_type ())
-#define MAI_ATK_SOCKET(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
-                                          MAI_TYPE_ATK_SOCKET, MaiAtkSocket))
-#define MAI_IS_ATK_SOCKET(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
-                                          MAI_TYPE_ATK_SOCKET))
-#define MAI_ATK_SOCKET_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass),\
-                                          MAI_TYPE_ATK_SOCKET,\
-                                          MaiAtkSocketClass))
-#define MAI_IS_ATK_SOCKET_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass),\
-                                          MAI_TYPE_ATK_SOCKET))
-#define MAI_ATK_SOCKET_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj),\
-                                          MAI_TYPE_ATK_SOCKET,\
-                                          MaiAtkSocketClass))
-
-typedef struct _MaiAtkSocket
-{
-  AtkSocket parent;
-
-  AccessibleWrap* accWrap;
-} MaiAtkSocket;
-
-typedef struct _MaiAtkSocketClass
-{
-  AtkSocketClass parent_class;
-} MaiAtkSocketClass;
 
 G_DEFINE_TYPE_EXTENDED(MaiAtkSocket, mai_atk_socket,
                        AtkSocketAccessible::g_atk_socket_type, 0,
                        G_IMPLEMENT_INTERFACE(ATK_TYPE_COMPONENT,
                                              mai_atk_component_iface_init))
 
 void
 mai_atk_socket_class_init(MaiAtkSocketClass* aAcc)
@@ -81,30 +52,30 @@ mai_atk_socket_new(AccessibleWrap* aAccW
 
 extern "C" {
 static AtkObject*
 RefAccessibleAtPoint(AtkComponent* aComponent, gint aX, gint aY,
                      AtkCoordType aCoordType)
 {
   NS_ENSURE_TRUE(MAI_IS_ATK_SOCKET(aComponent), nullptr);
 
-  return refAccessibleAtPointHelper(MAI_ATK_SOCKET(aComponent)->accWrap,
+  return refAccessibleAtPointHelper(ATK_OBJECT(MAI_ATK_SOCKET(aComponent)),
                                     aX, aY, aCoordType);
 }
 
 static void
 GetExtents(AtkComponent* aComponent, gint* aX, gint* aY, gint* aWidth,
            gint* aHeight, AtkCoordType aCoordType)
 {
   *aX = *aY = *aWidth = *aHeight = 0;
 
   if (!MAI_IS_ATK_SOCKET(aComponent))
     return;
 
-  getExtentsHelper(MAI_ATK_SOCKET(aComponent)->accWrap,
+  getExtentsHelper(ATK_OBJECT(MAI_ATK_SOCKET(aComponent)),
                    aX, aY, aWidth, aHeight, aCoordType);
 }
 }
 
 void
 mai_atk_component_iface_init(AtkComponentIface* aIface)
 {
   NS_ASSERTION(aIface, "Invalid Interface");
--- 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/InterfaceInitFuncs.h
+++ b/accessible/atk/InterfaceInitFuncs.h
@@ -29,15 +29,15 @@ void selectionInterfaceInitCB(AtkSelecti
 void tableInterfaceInitCB(AtkTableIface *aIface);
 void textInterfaceInitCB(AtkTextIface* aIface);
 void valueInterfaceInitCB(AtkValueIface *aIface);
 }
 
 /**
  * XXX these should live in a file of utils for atk.
  */
-AtkObject* refAccessibleAtPointHelper(mozilla::a11y::AccessibleWrap* aAccWrap,
+AtkObject* refAccessibleAtPointHelper(AtkObject* aAtkObj,
                                       gint aX, gint aY, AtkCoordType aCoordType);
-void getExtentsHelper(mozilla::a11y::AccessibleWrap* aAccWrap,
+void getExtentsHelper(AtkObject* aAtkObj,
                       gint* aX, gint* aY, gint* aWidth, gint* aHeight,
                       AtkCoordType aCoordType);
 
 #endif // ATK_INTERFACE_INIT_FUNCS_H_
--- a/accessible/atk/moz.build
+++ b/accessible/atk/moz.build
@@ -47,13 +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']
-
-FAIL_ON_WARNINGS = True
+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;
 }
 }
 
@@ -29,18 +30,49 @@ class ProxyAccessible;
                                          MAI_TYPE_ATK_OBJECT))
 #define IS_MAI_OBJECT_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), \
                                          MAI_TYPE_ATK_OBJECT))
 #define MAI_ATK_OBJECT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), \
                                          MAI_TYPE_ATK_OBJECT, \
                                          MaiAtkObjectClass))
 GType mai_atk_object_get_type(void);
 GType mai_util_get_type();
+extern "C" GType mai_atk_socket_get_type(void);
+
+/* MaiAtkSocket */
+
+#define MAI_TYPE_ATK_SOCKET              (mai_atk_socket_get_type ())
+#define MAI_ATK_SOCKET(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+                                          MAI_TYPE_ATK_SOCKET, MaiAtkSocket))
+#define MAI_IS_ATK_SOCKET(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+                                          MAI_TYPE_ATK_SOCKET))
+#define MAI_ATK_SOCKET_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass),\
+                                          MAI_TYPE_ATK_SOCKET,\
+                                          MaiAtkSocketClass))
+#define MAI_IS_ATK_SOCKET_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+                                          MAI_TYPE_ATK_SOCKET))
+#define MAI_ATK_SOCKET_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+                                          MAI_TYPE_ATK_SOCKET,\
+                                          MaiAtkSocketClass))
+
+typedef struct _MaiAtkSocket
+{
+  AtkSocket parent;
+
+  mozilla::a11y::AccessibleWrap* accWrap;
+} 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.
  */
@@ -60,27 +92,47 @@ 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.
    */
   void Shutdown();
 
   /*
    * Notify atk of a state change on this AtkObject.
    */
   void FireStateChangeEvent(uint64_t aState, bool aEnabled);
+
+  /*
+   * Notify ATK of a text change within this ATK object.
+   */
+  void FireTextChangeEvent(const nsString& aStr, int32_t aStart, uint32_t aLen,
+                           bool aIsInsert, bool aIsFromUser);
+
+private:
+  /*
+   * do we have text-remove and text-insert signals if not we need to use
+   * text-changed see AccessibleWrap::FireAtkTextChangedEvent() and
+   * bug 619002
+   */
+  enum EAvailableAtkSignals {
+    eUnknown,
+    eHaveNewAtkTextSignals,
+    eNoNewAtkSignals
+  };
+
+  static EAvailableAtkSignals gAvailableAtkSignals;
 };
 
 #endif /* __NS_MAI_H__ */
--- 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/nsMaiInterfaceAction.cpp
+++ b/accessible/atk/nsMaiInterfaceAction.cpp
@@ -5,107 +5,90 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "InterfaceInitFuncs.h"
 
 #include "Accessible-inl.h"
 #include "nsMai.h"
 #include "Role.h"
 #include "mozilla/Likely.h"
-
+#include "ProxyAccessible.h"
 #include "nsString.h"
 
 using namespace mozilla::a11y;
 
 extern "C" {
 
 static gboolean
 doActionCB(AtkAction *aAction, gint aActionIndex)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
-  return accWrap && accWrap->DoAction(aActionIndex);
+  if (accWrap) {
+    return accWrap->DoAction(aActionIndex);
+  }
+
+  ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction));
+  return proxy && proxy->DoAction(aActionIndex);
 }
 
 static gint
 getActionCountCB(AtkAction *aAction)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
-  return accWrap ? accWrap->ActionCount() : 0;
+  if (accWrap) {
+    return accWrap->ActionCount();
+  }
+
+  ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction));
+  return proxy ? proxy->ActionCount() : 0;
 }
 
 static const gchar*
 getActionDescriptionCB(AtkAction *aAction, gint aActionIndex)
 {
+  nsAutoString description;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
-  if (!accWrap)
+  if (accWrap) {
+    accWrap->ActionDescriptionAt(aActionIndex, description);
+  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction))) {
+    proxy->ActionDescriptionAt(aActionIndex, description);
+  } else {
     return nullptr;
+  }
 
-  nsAutoString description;
-  accWrap->ActionDescriptionAt(aActionIndex, description);
   return AccessibleWrap::ReturnString(description);
 }
 
 static const gchar*
 getActionNameCB(AtkAction *aAction, gint aActionIndex)
 {
+  nsAutoString autoStr;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
-  if (!accWrap)
+  if (accWrap) {
+    accWrap->ActionNameAt(aActionIndex, autoStr);
+  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction))) {
+    proxy->ActionNameAt(aActionIndex, autoStr);
+  } else {
     return nullptr;
+  }
 
-  nsAutoString autoStr;
-  accWrap->ActionNameAt(aActionIndex, autoStr);
   return AccessibleWrap::ReturnString(autoStr);
 }
 
 static const gchar*
 getKeyBindingCB(AtkAction *aAction, gint aActionIndex)
 {
+  nsAutoString keyBindingsStr;
   AccessibleWrap* acc = GetAccessibleWrap(ATK_OBJECT(aAction));
-  if (!acc)
+  if (acc) {
+    AccessibleWrap::GetKeyBinding(acc, keyBindingsStr);
+  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction))) {
+    proxy->AtkKeyBinding(keyBindingsStr);
+  } else {
     return nullptr;
-
-  // Return all key bindings including access key and keyboard shortcut.
-  nsAutoString keyBindingsStr;
-
-  // Get access key.
-  KeyBinding keyBinding = acc->AccessKey();
-  if (!keyBinding.IsEmpty()) {
-    keyBinding.AppendToString(keyBindingsStr, KeyBinding::eAtkFormat);
-
-    Accessible* parent = acc->Parent();
-    roles::Role role = parent ? parent->Role() : roles::NOTHING;
-    if (role == roles::PARENT_MENUITEM || role == roles::MENUITEM ||
-        role == roles::RADIO_MENU_ITEM || role == roles::CHECK_MENU_ITEM) {
-      // It is submenu, expose keyboard shortcuts from menu hierarchy like
-      // "s;<Alt>f:s"
-      nsAutoString keysInHierarchyStr = keyBindingsStr;
-      do {
-        KeyBinding parentKeyBinding = parent->AccessKey();
-        if (!parentKeyBinding.IsEmpty()) {
-          nsAutoString str;
-          parentKeyBinding.ToString(str, KeyBinding::eAtkFormat);
-          str.Append(':');
-
-          keysInHierarchyStr.Insert(str, 0);
-        }
-      } while ((parent = parent->Parent()) && parent->Role() != roles::MENUBAR);
-
-      keyBindingsStr.Append(';');
-      keyBindingsStr.Append(keysInHierarchyStr);
-    }
-  } else {
-    // No access key, add ';' to point this.
-    keyBindingsStr.Append(';');
-  }
-
-  // Get keyboard shortcut.
-  keyBindingsStr.Append(';');
-  keyBinding = acc->KeyboardShortcut();
-  if (!keyBinding.IsEmpty()) {
-    keyBinding.AppendToString(keyBindingsStr, KeyBinding::eAtkFormat);
   }
 
   return AccessibleWrap::ReturnString(keyBindingsStr);
 }
 }
 
 void
 actionInterfaceInitCB(AtkActionIface* aIface)
--- a/accessible/atk/nsMaiInterfaceComponent.cpp
+++ b/accessible/atk/nsMaiInterfaceComponent.cpp
@@ -6,100 +6,137 @@
 
 #include "InterfaceInitFuncs.h"
 
 #include "AccessibleWrap.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsMai.h"
 #include "mozilla/Likely.h"
+#include "mozilla/a11y/ProxyAccessible.h"
 
 using namespace mozilla::a11y;
 
 extern "C" {
 
 static AtkObject*
 refAccessibleAtPointCB(AtkComponent* aComponent, gint aAccX, gint aAccY,
                        AtkCoordType aCoordType)
 {
-  return refAccessibleAtPointHelper(GetAccessibleWrap(ATK_OBJECT(aComponent)),
+  return refAccessibleAtPointHelper(ATK_OBJECT(aComponent),
                                     aAccX, aAccY, aCoordType);
 }
 
 static void
 getExtentsCB(AtkComponent* aComponent, gint* aX, gint* aY,
              gint* aWidth, gint* aHeight, AtkCoordType aCoordType)
 {
-  getExtentsHelper(GetAccessibleWrap(ATK_OBJECT(aComponent)),
+  getExtentsHelper(ATK_OBJECT(aComponent),
                    aX, aY, aWidth, aHeight, aCoordType);
 }
 
 static gboolean
 grabFocusCB(AtkComponent* aComponent)
 {
-  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aComponent));
-  if (!accWrap)
-    return FALSE;
+  AtkObject* atkObject = ATK_OBJECT(aComponent);
+  AccessibleWrap* accWrap = GetAccessibleWrap(atkObject);
+  if (accWrap) {
+    accWrap->TakeFocus();
+    return TRUE;
+  }
 
-  accWrap->TakeFocus();
-  return TRUE;
+  ProxyAccessible* proxy = GetProxy(atkObject);
+  if (proxy) {
+    proxy->TakeFocus();
+    return TRUE;
+  }
+
+  return FALSE;
 }
 }
 
 AtkObject*
-refAccessibleAtPointHelper(AccessibleWrap* aAccWrap, gint aX, gint aY,
+refAccessibleAtPointHelper(AtkObject* aAtkObj, gint aX, gint aY,
                            AtkCoordType aCoordType)
 {
-  if (!aAccWrap || aAccWrap->IsDefunct() || nsAccUtils::MustPrune(aAccWrap))
-    return nullptr;
+  AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
+  if (accWrap) {
+    if (accWrap->IsDefunct() || nsAccUtils::MustPrune(accWrap)) {
+      return nullptr;
+    }
 
-  // Accessible::ChildAtPoint(x,y) is in screen pixels.
-  if (aCoordType == ATK_XY_WINDOW) {
-    nsIntPoint winCoords =
-      nsCoreUtils::GetScreenCoordsForWindow(aAccWrap->GetNode());
-    aX += winCoords.x;
-    aY += winCoords.y;
+    // Accessible::ChildAtPoint(x,y) is in screen pixels.
+    if (aCoordType == ATK_XY_WINDOW) {
+      nsIntPoint winCoords =
+        nsCoreUtils::GetScreenCoordsForWindow(accWrap->GetNode());
+      aX += winCoords.x;
+      aY += winCoords.y;
+    }
+
+    Accessible* accAtPoint = accWrap->ChildAtPoint(aX, aY,
+                                                   Accessible::eDirectChild);
+    if (!accAtPoint) {
+      return nullptr;
+    }
+
+    AtkObject* atkObj = AccessibleWrap::GetAtkObject(accAtPoint);
+    if (atkObj) {
+      g_object_ref(atkObj);
+    }
+
+    return atkObj;
   }
 
-  Accessible* accAtPoint = aAccWrap->ChildAtPoint(aX, aY,
-                                                  Accessible::eDirectChild);
-  if (!accAtPoint)
-    return nullptr;
+  if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
+    ProxyAccessible* result =
+      proxy->AccessibleAtPoint(aX, aY, aCoordType == ATK_XY_WINDOW);
+    AtkObject* atkObj = result ? GetWrapperFor(result) : nullptr;
+    if (atkObj) {
+      g_object_ref(atkObj);
+    }
+    return atkObj;
+  }
 
-  AtkObject* atkObj = AccessibleWrap::GetAtkObject(accAtPoint);
-  if (atkObj)
-    g_object_ref(atkObj);
-  return atkObj;
+  return nullptr;
 }
 
 void
-getExtentsHelper(AccessibleWrap* aAccWrap,
+getExtentsHelper(AtkObject* aAtkObj,
                  gint* aX, gint* aY, gint* aWidth, gint* aHeight,
                  AtkCoordType aCoordType)
 {
+  AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
   *aX = *aY = *aWidth = *aHeight = 0;
 
-  if (!aAccWrap || aAccWrap->IsDefunct())
-    return;
+  if (accWrap) {
+    if (accWrap->IsDefunct()) {
+      return;
+    }
+
+    nsIntRect screenRect = accWrap->Bounds();
+    if (screenRect.IsEmpty())
+      return;
 
-  nsIntRect screenRect = aAccWrap->Bounds();
-  if (screenRect.IsEmpty())
+    if (aCoordType == ATK_XY_WINDOW) {
+      nsIntPoint winCoords =
+        nsCoreUtils::GetScreenCoordsForWindow(accWrap->GetNode());
+      screenRect.x -= winCoords.x;
+      screenRect.y -= winCoords.y;
+    }
+
+    *aX = screenRect.x;
+    *aY = screenRect.y;
+    *aWidth = screenRect.width;
+    *aHeight = screenRect.height;
     return;
-
-  if (aCoordType == ATK_XY_WINDOW) {
-    nsIntPoint winCoords =
-      nsCoreUtils::GetScreenCoordsForWindow(aAccWrap->GetNode());
-    screenRect.x -= winCoords.x;
-    screenRect.y -= winCoords.y;
   }
 
-  *aX = screenRect.x;
-  *aY = screenRect.y;
-  *aWidth = screenRect.width;
-  *aHeight = screenRect.height;
+  if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
+    proxy->Extents(aCoordType == ATK_XY_WINDOW, aX, aY, aWidth, aHeight);
+  }
 }
 
 void
 componentInterfaceInitCB(AtkComponentIface* aIface)
 {
   NS_ASSERTION(aIface, "Invalid Interface");
   if(MOZ_UNLIKELY(!aIface))
     return;
--- a/accessible/atk/nsMaiInterfaceTable.cpp
+++ b/accessible/atk/nsMaiInterfaceTable.cpp
@@ -7,205 +7,260 @@
 #include "InterfaceInitFuncs.h"
 
 #include "Accessible-inl.h"
 #include "AccessibleWrap.h"
 #include "nsAccUtils.h"
 #include "TableAccessible.h"
 #include "TableCellAccessible.h"
 #include "nsMai.h"
-
+#include "ProxyAccessible.h"
 #include "nsArrayUtils.h"
 
 #include "mozilla/Likely.h"
 
 using namespace mozilla::a11y;
 
 extern "C" {
 static AtkObject*
 refAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx)
 {
+  if (aRowIdx < 0 || aColIdx < 0) {
+    return nullptr;
+  }
+
+  AtkObject* cellAtkObj = nullptr;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap || aRowIdx < 0 || aColIdx < 0)
-    return nullptr;
+  if (accWrap) {
+    Accessible* cell = accWrap->AsTable()->CellAt(aRowIdx, aColIdx);
+    if (!cell) {
+      return nullptr;
+    }
 
-  Accessible* cell = accWrap->AsTable()->CellAt(aRowIdx, aColIdx);
-  if (!cell)
-    return nullptr;
+    cellAtkObj = AccessibleWrap::GetAtkObject(cell);
+  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    ProxyAccessible* cell = proxy->TableCellAt(aRowIdx, aColIdx);
+    if (!cell) {
+      return nullptr;
+    }
 
-  AtkObject* cellAtkObj = AccessibleWrap::GetAtkObject(cell);
-  if (cellAtkObj)
+    cellAtkObj = GetWrapperFor(cell);
+  }
+
+  if (cellAtkObj) {
     g_object_ref(cellAtkObj);
+  }
 
   return cellAtkObj;
 }
 
 static gint
 getIndexAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx)
 {
-  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap || aRowIdx < 0 || aColIdx < 0)
+  if (aRowIdx < 0 || aColIdx < 0) {
     return -1;
+  }
 
-  return static_cast<gint>(accWrap->AsTable()->CellIndexAt(aRowIdx, aColIdx));
+  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+  if (accWrap) {
+    return static_cast<gint>(accWrap->AsTable()->CellIndexAt(aRowIdx, aColIdx));
+  }
+
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    return static_cast<gint>(proxy->TableCellIndexAt(aRowIdx, aColIdx));
+  }
+
+  return -1;
 }
 
 static gint
 getColumnAtIndexCB(AtkTable *aTable, gint aIdx)
 {
-  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap || aIdx < 0)
+  if (aIdx < 0) {
     return -1;
+  }
 
+  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+  if (accWrap) {
     return static_cast<gint>(accWrap->AsTable()->ColIndexAt(aIdx));
+  }
+
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    return static_cast<gint>(proxy->TableColumnIndexAt(aIdx));
+  }
+
+  return -1;
 }
 
 static gint
 getRowAtIndexCB(AtkTable *aTable, gint aIdx)
 {
-  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap || aIdx < 0)
+  if (aIdx < 0) {
     return -1;
+  }
 
+  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+  if (accWrap) {
     return static_cast<gint>(accWrap->AsTable()->RowIndexAt(aIdx));
+  }
+
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    return static_cast<gint>(proxy->TableRowIndexAt(aIdx));
+  }
+
+  return -1;
 }
 
 static gint
 getColumnCountCB(AtkTable *aTable)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap)
-    return -1;
+  if (accWrap) {
+    return static_cast<gint>(accWrap->AsTable()->ColCount());
+  }
 
-    return static_cast<gint>(accWrap->AsTable()->ColCount());
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    return static_cast<gint>(proxy->TableColumnCount());
+  }
+
+  return -1;
 }
 
 static gint
 getRowCountCB(AtkTable *aTable)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap)
-    return -1;
+  if (accWrap) {
+    return static_cast<gint>(accWrap->AsTable()->RowCount());
+  }
 
-    return static_cast<gint>(accWrap->AsTable()->RowCount());
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    return static_cast<gint>(proxy->TableRowCount());
+  }
+
+  return -1;
 }
 
 static gint
 getColumnExtentAtCB(AtkTable *aTable, gint aRowIdx, gint aColIdx)
 {
-  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap || aRowIdx < 0 || aColIdx < 0)
+  if (aRowIdx < 0 || aColIdx < 0) {
     return -1;
+  }
 
+  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+  if (accWrap) {
     return static_cast<gint>(accWrap->AsTable()->ColExtentAt(aRowIdx, aColIdx));
+  }
+
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    return static_cast<gint>(proxy->TableColumnExtentAt(aRowIdx, aColIdx));
+  }
+
+  return -1;
 }
 
 static gint
 getRowExtentAtCB(AtkTable *aTable, gint aRowIdx, gint aColIdx)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap)
-    return -1;
+  if (accWrap) {
+    return static_cast<gint>(accWrap->AsTable()->RowExtentAt(aRowIdx, aColIdx));
+  }
 
-  return static_cast<gint>(accWrap->AsTable()->RowExtentAt(aRowIdx, aColIdx));
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    return static_cast<gint>(proxy->TableRowExtentAt(aRowIdx, aColIdx));
+  }
+
+  return -1;
 }
 
 static AtkObject*
 getCaptionCB(AtkTable* aTable)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap)
-    return nullptr;
+  if (accWrap) {
+    Accessible* caption = accWrap->AsTable()->Caption();
+    return caption ? AccessibleWrap::GetAtkObject(caption) : nullptr;
+  }
 
-  Accessible* caption = accWrap->AsTable()->Caption();
-  return caption ? AccessibleWrap::GetAtkObject(caption) : nullptr;
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    ProxyAccessible* caption = proxy->TableCaption();
+    return caption ? GetWrapperFor(caption) : nullptr;
+  }
+
+  return nullptr;
 }
 
 static const gchar*
 getColumnDescriptionCB(AtkTable *aTable, gint aColumn)
 {
+  nsAutoString autoStr;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap)
+  if (accWrap) {
+    accWrap->AsTable()->ColDescription(aColumn, autoStr);
+  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    proxy->TableColumnDescription(aColumn, autoStr);
+  } else {
     return nullptr;
-
-  nsAutoString autoStr;
-  accWrap->AsTable()->ColDescription(aColumn, autoStr);
+  }
 
   return AccessibleWrap::ReturnString(autoStr);
 }
 
 static AtkObject*
 getColumnHeaderCB(AtkTable *aTable, gint aColIdx)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap)
-    return nullptr;
-
-  Accessible* cell = accWrap->AsTable()->CellAt(0, aColIdx);
-  if (!cell)
-    return nullptr;
-
-  // If the cell at the first row is column header then assume it is column
-  // header for all rows,
-  if (cell->Role() == roles::COLUMNHEADER)
-    return AccessibleWrap::GetAtkObject(cell);
+  if (accWrap) {
+    Accessible* header =
+      AccessibleWrap::GetColumnHeader(accWrap->AsTable(), aColIdx);
+    return header ? AccessibleWrap::GetAtkObject(header) : nullptr;
+  }
 
-  // otherwise get column header for the data cell at the first row.
-  TableCellAccessible* tableCell = cell->AsTableCell();
-  if (!tableCell)
-    return nullptr;
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    ProxyAccessible* header = proxy->AtkTableColumnHeader(aColIdx);
+    return header ? GetWrapperFor(header) : nullptr;
+  }
 
-  nsAutoTArray<Accessible*, 10> headerCells;
-  tableCell->ColHeaderCells(&headerCells);
-  if (headerCells.IsEmpty())
-    return nullptr;
-
-  return AccessibleWrap::GetAtkObject(headerCells[0]);
+  return nullptr;
 }
 
 static const gchar*
 getRowDescriptionCB(AtkTable *aTable, gint aRow)
 {
+  nsAutoString autoStr;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap)
+  if (accWrap) {
+    accWrap->AsTable()->RowDescription(aRow, autoStr);
+  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    proxy->TableRowDescription(aRow, autoStr);
+  } else {
     return nullptr;
-
-  nsAutoString autoStr;
-  accWrap->AsTable()->RowDescription(aRow, autoStr);
+  }
 
   return AccessibleWrap::ReturnString(autoStr);
 }
 
 static AtkObject*
 getRowHeaderCB(AtkTable *aTable, gint aRowIdx)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap)
-    return nullptr;
-
-  Accessible* cell = accWrap->AsTable()->CellAt(aRowIdx, 0);
-  if (!cell)
-    return nullptr;
-
-  // If the cell at the first column is row header then assume it is row
-  // header for all columns,
-  if (cell->Role() == roles::ROWHEADER)
-    return AccessibleWrap::GetAtkObject(cell);
+  if (accWrap) {
+    Accessible* header =
+      AccessibleWrap::GetRowHeader(accWrap->AsTable(), aRowIdx);
+    return header ? AccessibleWrap::GetAtkObject(header) : nullptr;
+  }
 
-  // otherwise get row header for the data cell at the first column.
-  TableCellAccessible* tableCell = cell->AsTableCell();
-  if (!tableCell)
-    return nullptr;
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    ProxyAccessible* header = proxy->AtkTableRowHeader(aRowIdx);
+    return header ? GetWrapperFor(header) : nullptr;
+  }
 
-  nsAutoTArray<Accessible*, 10> headerCells;
-  tableCell->RowHeaderCells(&headerCells);
-  if (headerCells.IsEmpty())
-    return nullptr;
-
-  return AccessibleWrap::GetAtkObject(headerCells[0]);
+  return nullptr;
 }
 
 static AtkObject*
 getSummaryCB(AtkTable *aTable)
 {
   // Neither html:table nor xul:tree nor ARIA grid/tree have an ability to
   // link an accessible object to specify a summary. There is closes method
   // in TableAccessible::summary to get a summary as a string which is not
@@ -213,22 +268,26 @@ getSummaryCB(AtkTable *aTable)
   return nullptr;
 }
 
 static gint
 getSelectedColumnsCB(AtkTable *aTable, gint** aSelected)
 {
   *aSelected = nullptr;
 
+  AutoTArray<uint32_t, 10> cols;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap)
+  if (accWrap) {
+    accWrap->AsTable()->SelectedColIndices(&cols);
+   } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    proxy->TableSelectedColumnIndices(&cols);
+  } else {
     return 0;
+  }
 
-  nsAutoTArray<uint32_t, 10> cols;
-  accWrap->AsTable()->SelectedColIndices(&cols);
   if (cols.IsEmpty())
     return 0;
 
   gint* atkColumns = g_new(gint, cols.Length());
   if (!atkColumns) {
     NS_WARNING("OUT OF MEMORY");
     return 0;
   }
@@ -236,63 +295,75 @@ 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)
 {
+  AutoTArray<uint32_t, 10> rows;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap)
+  if (accWrap) {
+    accWrap->AsTable()->SelectedRowIndices(&rows);
+  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    proxy->TableSelectedRowIndices(&rows);
+  } else {
     return 0;
-
-  nsAutoTArray<uint32_t, 10> rows;
-  accWrap->AsTable()->SelectedRowIndices(&rows);
+  }
 
   gint* atkRows = g_new(gint, rows.Length());
   if (!atkRows) {
     NS_WARNING("OUT OF MEMORY");
     return 0;
   }
 
   memcpy(atkRows, rows.Elements(), rows.Length() * sizeof(uint32_t));
   *aSelected = atkRows;
   return rows.Length();
 }
 
 static gboolean
 isColumnSelectedCB(AtkTable *aTable, gint aColIdx)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap)
-    return FALSE;
+  if (accWrap) {
+    return static_cast<gboolean>(accWrap->AsTable()->IsColSelected(aColIdx));
+  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    return static_cast<gboolean>(proxy->TableColumnSelected(aColIdx));
+  }
 
-  return static_cast<gboolean>(accWrap->AsTable()->IsColSelected(aColIdx));
+  return FALSE;
 }
 
 static gboolean
 isRowSelectedCB(AtkTable *aTable, gint aRowIdx)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap)
-    return FALSE;
+  if (accWrap) {
+    return static_cast<gboolean>(accWrap->AsTable()->IsRowSelected(aRowIdx));
+  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    return static_cast<gboolean>(proxy->TableRowSelected(aRowIdx));
+  }
 
-  return static_cast<gboolean>(accWrap->AsTable()->IsRowSelected(aRowIdx));
+  return FALSE;
 }
 
 static gboolean
 isCellSelectedCB(AtkTable *aTable, gint aRowIdx, gint aColIdx)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
-  if (!accWrap)
-    return FALSE;
-
+  if (accWrap) {
     return static_cast<gboolean>(accWrap->AsTable()->
       IsCellSelected(aRowIdx, aColIdx));
+  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+    return static_cast<gboolean>(proxy->TableCellSelected(aRowIdx, aColIdx));
+  }
+
+  return FALSE;
 }
 }
 
 void
 tableInterfaceInitCB(AtkTableIface* aIface)
 {
   NS_ASSERTION(aIface, "no interface!");
   if (MOZ_UNLIKELY(!aIface))
--- a/accessible/atk/nsMaiInterfaceText.cpp
+++ b/accessible/atk/nsMaiInterfaceText.cpp
@@ -158,58 +158,63 @@ getTextCB(AtkText *aText, gint aStartOff
   return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
 }
 
 static gchar*
 getTextAfterOffsetCB(AtkText *aText, gint aOffset,
                      AtkTextBoundary aBoundaryType,
                      gint *aStartOffset, gint *aEndOffset)
 {
+    nsAutoString autoStr;
+  int32_t startOffset = 0, endOffset = 0;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
-  if (!accWrap)
-    return nullptr;
+  if (accWrap) {
+    HyperTextAccessible* text = accWrap->AsHyperText();
+    if (!text || !text->IsTextRole())
+      return nullptr;
 
-  HyperTextAccessible* text = accWrap->AsHyperText();
-  if (!text || !text->IsTextRole())
-    return nullptr;
-
-  nsAutoString autoStr;
-  int32_t startOffset = 0, endOffset = 0;
-  text->TextAfterOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
+    text->TextAfterOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
+    ConvertTexttoAsterisks(accWrap, autoStr);
+  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+    proxy->GetTextAfterOffset(aOffset, aBoundaryType, autoStr, &startOffset,
+                              &endOffset);
+  }
 
   *aStartOffset = startOffset;
   *aEndOffset = endOffset;
 
-  ConvertTexttoAsterisks(accWrap, autoStr);
   NS_ConvertUTF16toUTF8 cautoStr(autoStr);
   return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
 }
 
 static gchar*
 getTextAtOffsetCB(AtkText *aText, gint aOffset,
                   AtkTextBoundary aBoundaryType,
                   gint *aStartOffset, gint *aEndOffset)
 {
+  nsAutoString autoStr;
+  int32_t startOffset = 0, endOffset = 0;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
-  if (!accWrap)
-    return nullptr;
-
-  HyperTextAccessible* text = accWrap->AsHyperText();
-  if (!text || !text->IsTextRole())
-    return nullptr;
+  if (accWrap) {
+    HyperTextAccessible* text = accWrap->AsHyperText();
+    if (!text || !text->IsTextRole())
+      return nullptr;
 
-    nsAutoString autoStr;
-    int32_t startOffset = 0, endOffset = 0;
     text->TextAtOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
-    *aStartOffset = startOffset;
-    *aEndOffset = endOffset;
+    ConvertTexttoAsterisks(accWrap, autoStr);
+  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+    proxy->GetTextAtOffset(aOffset, aBoundaryType, autoStr, &startOffset,
+                           &endOffset);
+  }
 
-    ConvertTexttoAsterisks(accWrap, autoStr);
-    NS_ConvertUTF16toUTF8 cautoStr(autoStr);
-    return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
+  *aStartOffset = startOffset;
+  *aEndOffset = endOffset;
+
+  NS_ConvertUTF16toUTF8 cautoStr(autoStr);
+  return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
 }
 
 static gunichar
 getCharacterAtOffsetCB(AtkText* aText, gint aOffset)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (accWrap) {
     HyperTextAccessible* text = accWrap->AsHyperText();
@@ -228,32 +233,35 @@ getCharacterAtOffsetCB(AtkText* aText, g
   return 0;
 }
 
 static gchar*
 getTextBeforeOffsetCB(AtkText *aText, gint aOffset,
                       AtkTextBoundary aBoundaryType,
                       gint *aStartOffset, gint *aEndOffset)
 {
-  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
-  if (!accWrap)
-    return nullptr;
-
-  HyperTextAccessible* text = accWrap->AsHyperText();
-  if (!text || !text->IsTextRole())
-    return nullptr;
-
   nsAutoString autoStr;
   int32_t startOffset = 0, endOffset = 0;
-  text->TextBeforeOffset(aOffset, aBoundaryType,
-                         &startOffset, &endOffset, autoStr);
+  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+  if (accWrap) {
+    HyperTextAccessible* text = accWrap->AsHyperText();
+    if (!text || !text->IsTextRole())
+      return nullptr;
+
+    text->TextBeforeOffset(aOffset, aBoundaryType,
+                           &startOffset, &endOffset, autoStr);
+    ConvertTexttoAsterisks(accWrap, autoStr);
+  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+    proxy->GetTextBeforeOffset(aOffset, aBoundaryType, autoStr, &startOffset,
+                               &endOffset);
+  }
+
   *aStartOffset = startOffset;
   *aEndOffset = endOffset;
 
-  ConvertTexttoAsterisks(accWrap, autoStr);
   NS_ConvertUTF16toUTF8 cautoStr(autoStr);
   return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
 }
 
 static gint
 getCaretOffsetCB(AtkText *aText)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
@@ -298,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)
@@ -324,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,
@@ -573,19 +581,18 @@ setCaretOffsetCB(AtkText *aText, gint aO
       return FALSE;
     }
 
     text->SetCaretOffset(aOffset);
     return TRUE;
   }
 
   if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
-    if (proxy->SetCaretOffset(aOffset)) {
-      return TRUE;
-    }
+    proxy->SetCaretOffset(aOffset);
+    return TRUE;
   }
 
   return FALSE;
 }
 }
 
 void
 textInterfaceInitCB(AtkTextIface* aIface)
--- 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/AccCollector.cpp
+++ b/accessible/base/AccCollector.cpp
@@ -97,21 +97,23 @@ AccCollector::AppendObject(Accessible* a
 ////////////////////////////////////////////////////////////////////////////////
 
 int32_t
 EmbeddedObjCollector::GetIndexAt(Accessible* aAccessible)
 {
   if (aAccessible->mParent != mRoot)
     return -1;
 
-  if (aAccessible->mIndexOfEmbeddedChild != -1)
-    return aAccessible->mIndexOfEmbeddedChild;
+  MOZ_ASSERT(!aAccessible->IsProxy());
+  if (aAccessible->mInt.mIndexOfEmbeddedChild != -1)
+    return aAccessible->mInt.mIndexOfEmbeddedChild;
 
   return mFilterFunc(aAccessible) & filters::eMatch ?
     EnsureNGetIndex(aAccessible) : -1;
 }
 
 void
 EmbeddedObjCollector::AppendObject(Accessible* aAccessible)
 {
-  aAccessible->mIndexOfEmbeddedChild = mObjects.Length();
+  MOZ_ASSERT(!aAccessible->IsProxy());
+  aAccessible->mInt.mIndexOfEmbeddedChild = mObjects.Length();
   mObjects.AppendElement(aAccessible);
 }
--- a/accessible/base/AccEvent.cpp
+++ b/accessible/base/AccEvent.cpp
@@ -99,31 +99,32 @@ AccReorderEvent::IsShowHideEventTarget(c
   return 0;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccHideEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 AccHideEvent::
-  AccHideEvent(Accessible* aTarget, nsINode* aTargetNode) :
-  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
@@ -122,17 +122,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(AccEvent)
 
 protected:
   virtual ~AccEvent() {}
 
   bool mIsFromUserInput;
   uint32_t mEventType;
   EEventRule mEventRule;
-  nsRefPtr<Accessible> mAccessible;
+  RefPtr<Accessible> mAccessible;
 
   friend class EventQueue;
   friend class AccReorderEvent;
 };
 
 
 /**
  * Accessible state change event.
@@ -189,16 +189,17 @@ public:
   }
 
   // AccTextChangeEvent
   int32_t GetStartOffset() const { return mStart; }
   uint32_t GetLength() const { return mModifiedText.Length(); }
   bool IsTextInserted() const { return mIsInserted; }
   void GetModifiedText(nsAString& aModifiedText)
     { aModifiedText = mModifiedText; }
+  const nsString& ModifiedText() const { return mModifiedText; }
 
 private:
   int32_t mStart;
   bool mIsInserted;
   nsString mModifiedText;
 
   friend class EventQueue;
   friend class AccReorderEvent;
@@ -206,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() { }
 
@@ -231,58 +231,60 @@ public:
   // MutationEvent
   bool IsShow() const { return mEventType == nsIAccessibleEvent::EVENT_SHOW; }
   bool IsHide() const { return mEventType == nsIAccessibleEvent::EVENT_HIDE; }
 
   Accessible* Parent() const { return mParent; }
 
 protected:
   nsCOMPtr<nsINode> mNode;
-  nsRefPtr<Accessible> mParent;
-  nsRefPtr<AccTextChangeEvent> mTextChangeEvent;
+  RefPtr<Accessible> mParent;
+  RefPtr<AccTextChangeEvent> mTextChangeEvent;
 
   friend class EventQueue;
 };
 
 
 /**
  * Accessible hide event.
  */
 class AccHideEvent: public AccMutationEvent
 {
 public:
-  AccHideEvent(Accessible* aTarget, nsINode* aTargetNode);
+  explicit AccHideEvent(Accessible* aTarget, bool aNeedsShutdown = true);
 
   // Event
   static const EventGroup kEventGroup = eHideEvent;
   virtual unsigned int GetEventGroups() const override
   {
     return AccMutationEvent::GetEventGroups() | (1U << eHideEvent);
   }
 
   // AccHideEvent
   Accessible* TargetParent() const { return mParent; }
   Accessible* TargetNextSibling() const { return mNextSibling; }
   Accessible* TargetPrevSibling() const { return mPrevSibling; }
+  bool NeedsShutdown() const { return mNeedsShutdown; }
 
 protected:
-  nsRefPtr<Accessible> mNextSibling;
-  nsRefPtr<Accessible> mPrevSibling;
+  bool mNeedsShutdown;
+  RefPtr<Accessible> mNextSibling;
+  RefPtr<Accessible> mPrevSibling;
 
   friend class EventQueue;
 };
 
 
 /**
  * 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);
   }
 };
@@ -388,17 +390,17 @@ public:
   // AccTextSelChangeEvent
 
   /**
    * Return true if the text selection change wasn't caused by pure caret move.
    */
   bool IsCaretMoveOnly() const;
 
 private:
-  nsRefPtr<dom::Selection> mSel;
+  RefPtr<dom::Selection> mSel;
   int32_t mReason;
 
   friend class EventQueue;
   friend class SelectionManager;
 };
 
 
 /**
@@ -423,18 +425,18 @@ public:
   {
     return AccEvent::GetEventGroups() | (1U << eSelectionChangeEvent);
   }
 
   // AccSelChangeEvent
   Accessible* Widget() const { return mWidget; }
 
 private:
-  nsRefPtr<Accessible> mWidget;
-  nsRefPtr<Accessible> mItem;
+  RefPtr<Accessible> mWidget;
+  RefPtr<Accessible> mItem;
   SelChangeType mSelChangeType;
   uint32_t mPreceedingCount;
   AccSelChangeEvent* mPackedEvent;
 
   friend class EventQueue;
 };
 
 
@@ -486,17 +488,17 @@ public:
 
   // AccTableChangeEvent
   Accessible* OldAccessible() const { return mOldAccessible; }
   int32_t OldStartOffset() const { return mOldStart; }
   int32_t OldEndOffset() const { return mOldEnd; }
   int32_t Reason() const { return mReason; }
 
 private:
-  nsRefPtr<Accessible> mOldAccessible;
+  RefPtr<Accessible> mOldAccessible;
   int32_t mOldStart;
   int32_t mOldEnd;
   int16_t mReason;
 };
 
 /**
  * Accessible object attribute changed event.
  */
--- a/accessible/base/AccIterator.cpp
+++ b/accessible/base/AccIterator.cpp
@@ -4,17 +4,17 @@
 
 #include "AccIterator.h"
 
 #include "AccGroupInfo.h"
 #ifdef MOZ_XUL
 #include "XULTreeAccessible.h"
 #endif
 
-#include "mozilla/dom/Element.h"
+#include "mozilla/dom/HTMLLabelElement.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccIterator
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -129,44 +129,53 @@ RelatedAccIterator::Next()
 HTMLLabelIterator::
   HTMLLabelIterator(DocAccessible* aDocument, const Accessible* aAccessible,
                     LabelFilter aFilter) :
   mRelIter(aDocument, aAccessible->GetContent(), nsGkAtoms::_for),
   mAcc(aAccessible), mLabelFilter(aFilter)
 {
 }
 
+bool
+HTMLLabelIterator::IsLabel(Accessible* aLabel)
+{
+  dom::HTMLLabelElement* labelEl =
+    dom::HTMLLabelElement::FromContent(aLabel->GetContent());
+  return labelEl && labelEl->GetControl() == mAcc->GetContent();
+}
+
 Accessible*
 HTMLLabelIterator::Next()
 {
   // Get either <label for="[id]"> element which explicitly points to given
   // element, or <label> ancestor which implicitly point to it.
   Accessible* label = nullptr;
   while ((label = mRelIter.Next())) {
-    if (label->GetContent()->IsHTMLElement(nsGkAtoms::label))
+    if (IsLabel(label)) {
       return label;
+    }
   }
 
   // Ignore ancestor label on not widget accessible.
   if (mLabelFilter == eSkipAncestorLabel || !mAcc->IsWidget())
     return nullptr;
 
   // Go up tree to get a name of ancestor label if there is one (an ancestor
   // <label> implicitly points to us). Don't go up farther than form or
   // document.
   Accessible* walkUp = mAcc->Parent();
   while (walkUp && !walkUp->IsDoc()) {
-    nsIContent* walkUpElm = walkUp->GetContent();
-    if (walkUpElm->IsHTMLElement(nsGkAtoms::label) &&
-        !walkUpElm->HasAttr(kNameSpaceID_None, nsGkAtoms::_for)) {
+    nsIContent* walkUpEl = walkUp->GetContent();
+    if (IsLabel(walkUp) &&
+        !walkUpEl->HasAttr(kNameSpaceID_None, nsGkAtoms::_for)) {
       mLabelFilter = eSkipAncestorLabel; // prevent infinite loop
       return walkUp;
     }
 
-    if (walkUpElm->IsHTMLElement(nsGkAtoms::form))
+    if (walkUpEl->IsHTMLElement(nsGkAtoms::form))
       break;
 
     walkUp = walkUp->Parent();
   }
 
   return nullptr;
 }
 
@@ -319,89 +328,40 @@ IDRefsIterator::GetElem(const nsDependen
   }
 
   return nullptr;
 }
 
 Accessible*
 IDRefsIterator::Next()
 {
-  nsIContent* nextElm = NextElem();
-  return nextElm ? mDoc->GetAccessible(nextElm) : nullptr;
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-// ARIAOwnedByIterator
-////////////////////////////////////////////////////////////////////////////////
-
-ARIAOwnedByIterator::ARIAOwnedByIterator(const Accessible* aDependent) :
-  RelatedAccIterator(aDependent->Document(), aDependent->GetContent(),
-                     nsGkAtoms::aria_owns), mDependent(aDependent)
-{
-}
-
-Accessible*
-ARIAOwnedByIterator::Next()
-{
-  Accessible* owner = RelatedAccIterator::Next();
-  Accessible* cur = owner;
-  while (cur) {
-    if (cur == mDependent)
-      return Next(); // owner cannot be a child of dependent.
-
-    if (cur->IsDoc())
-      break; // don't cross document boundaries
-
-    cur = cur->Parent();
+  nsIContent* nextEl = nullptr;
+  while ((nextEl = NextElem())) {
+    Accessible* acc = mDoc->GetAccessible(nextEl);
+    if (acc) {
+      return acc;
+    }
   }
-
-  return owner;
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-// ARIAOwnsIterator
-////////////////////////////////////////////////////////////////////////////////
-
-ARIAOwnsIterator::ARIAOwnsIterator(const Accessible* aOwner) :
-  mIter(aOwner->Document(), aOwner->GetContent(), nsGkAtoms::aria_owns),
-  mOwner(aOwner)
-{
-}
-
-Accessible*
-ARIAOwnsIterator::Next()
-{
-  Accessible* child = mIter.Next();
-  const Accessible* cur = mOwner;
-  while (cur) {
-    if (cur == child)
-      return Next(); // cannot own its own parent
-
-    if (cur->IsDoc())
-      break; // don't cross document boundaries
-
-    cur = cur->Parent();
-  }
-
-  return child;
+  return nullptr;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // SingleAccIterator
 ////////////////////////////////////////////////////////////////////////////////
 
 Accessible*
 SingleAccIterator::Next()
 {
-  nsRefPtr<Accessible> nextAcc;
+  RefPtr<Accessible> nextAcc;
   mAcc.swap(nextAcc);
-  return (nextAcc && !nextAcc->IsDefunct()) ? nextAcc : nullptr;
+  if (!nextAcc || nextAcc->IsDefunct()) {
+    return nullptr;
+  }
+  return nextAcc;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // ItemIterator
 ////////////////////////////////////////////////////////////////////////////////
 
 Accessible*
--- a/accessible/base/AccIterator.h
+++ b/accessible/base/AccIterator.h
@@ -125,16 +125,18 @@ public:
    */
   virtual Accessible* Next() override;
 
 private:
   HTMLLabelIterator();
   HTMLLabelIterator(const HTMLLabelIterator&);
   HTMLLabelIterator& operator = (const HTMLLabelIterator&);
 
+  bool IsLabel(Accessible* aLabel);
+
   RelatedAccIterator mRelIter;
   // XXX: replace it on weak reference (bug 678429), it's safe to use raw
   // pointer now because iterators life cycle is short.
   const Accessible* mAcc;
   LabelFilter mLabelFilter;
 };
 
 
@@ -244,74 +246,33 @@ private:
   nsString mIDs;
   nsIContent* mContent;
   DocAccessible* mDoc;
   nsAString::index_type mCurrIdx;
 };
 
 
 /**
- * Iterates over related accessible referred by aria-owns.
- */
-class ARIAOwnedByIterator final : public RelatedAccIterator
-{
-public:
-  explicit ARIAOwnedByIterator(const Accessible* aDependent);
-  virtual ~ARIAOwnedByIterator() { }
-
-  virtual Accessible* Next() override;
-
-private:
-  ARIAOwnedByIterator() = delete;
-  ARIAOwnedByIterator(const ARIAOwnedByIterator&) = delete;
-  ARIAOwnedByIterator& operator = (const ARIAOwnedByIterator&) = delete;
-
-  const Accessible* mDependent;
-};
-
-
-/**
- * Iterates over related accessible referred by aria-owns.
- */
-class ARIAOwnsIterator final : public AccIterable
-{
-public:
-  explicit ARIAOwnsIterator(const Accessible* aOwner);
-  virtual ~ARIAOwnsIterator() { }
-
-  virtual Accessible* Next() override;
-
-private:
-  ARIAOwnsIterator() = delete;
-  ARIAOwnsIterator(const ARIAOwnsIterator&) = delete;
-  ARIAOwnsIterator& operator = (const ARIAOwnsIterator&) = delete;
-
-  IDRefsIterator mIter;
-  const Accessible* mOwner;
-};
-
-
-/**
  * Iterator that points to a single accessible returning it on the first call
  * to Next().
  */
 class SingleAccIterator : public AccIterable
 {
 public:
   explicit SingleAccIterator(Accessible* aTarget): mAcc(aTarget) { }
   virtual ~SingleAccIterator() { }
 
   virtual Accessible* Next() override;
 
 private:
   SingleAccIterator();
   SingleAccIterator(const SingleAccIterator&);
   SingleAccIterator& operator = (const SingleAccIterator&);
 
-  nsRefPtr<Accessible> mAcc;
+  RefPtr<Accessible> mAcc;
 };
 
 
 /**
  * Used to iterate items of the given item container.
  */
 class ItemIterator : public AccIterable
 {
--- 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
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DocManager.h"
 
 #include "ApplicationAccessible.h"
 #include "ARIAMap.h"
@@ -20,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)
 {
@@ -66,62 +68,104 @@ DocManager::GetDocAccessible(nsIDocument
     return docAcc;
 
   return CreateDocOrRootAccessible(aDocument);
 }
 
 Accessible*
 DocManager::FindAccessibleInCache(nsINode* aNode) const
 {
-  nsSearchAccessibleInCacheArg arg;
-  arg.mNode = aNode;
+  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!");
 
-  mDocAccessibleCache.EnumerateRead(SearchAccessibleInDocCache,
-                                    static_cast<void*>(&arg));
-
-  return arg.mAccessible;
+    if (docAccessible) {
+      Accessible* accessible = docAccessible->GetAccessible(aNode);
+      if (accessible) {
+        return accessible;
+      }
+    }
+  }
+  return nullptr;
 }
 
 void
 DocManager::NotifyOfDocumentShutdown(DocAccessible* aDocument,
                                      nsIDocument* aDOMDocument)
 {
   xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
   if (xpcDoc) {
     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
 {
-  bool isDocRefreshing = false;
-  mDocAccessibleCache.EnumerateRead(SearchIfDocIsRefreshing,
-                                    static_cast<void*>(&isDocRefreshing));
+  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!");
 
-  return isDocRefreshing;
+    if (docAccessible && docAccessible->mNotificationController &&
+        docAccessible->mNotificationController->IsUpdating()) {
+      return true;
+    }
+  }
+  return false;
 }
 #endif
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocManager protected
 
 bool
@@ -168,25 +212,25 @@ 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<nsIDOMDocument> DOMDocument;
-  DOMWindow->GetDocument(getter_AddRefs(DOMDocument));
-  NS_ENSURE_STATE(DOMDocument);
+  nsPIDOMWindowOuter* piWindow = nsPIDOMWindowOuter::From(DOMWindow);
+  MOZ_ASSERT(piWindow);
 
-  nsCOMPtr<nsIDocument> document(do_QueryInterface(DOMDocument));
+  nsCOMPtr<nsIDocument> document = piWindow->GetDoc();
+  NS_ENSURE_STATE(document);
 
   // Document was loaded.
   if (aStateFlags & STATE_STOP) {
 #ifdef A11Y_LOG
     if (logging::IsEnabled(logging::eDocLoad))
       logging::DocLoad("document loaded", aWebProgress, aRequest, aStateFlags);
 #endif
 
@@ -353,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");
@@ -377,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();
@@ -421,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);
-  nsRefPtr<DocAccessible> docAcc = isRootDoc ?
-    new RootAccessibleWrap(aDocument, rootElm, presShell) :
-    new DocAccessibleWrap(aDocument, rootElm, presShell);
+  RefPtr<DocAccessible> docAcc = isRootDoc ?
+    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;
     }
 
@@ -450,22 +492,30 @@ DocManager::CreateDocOrRootAccessible(ns
     // constructed because event processing and tree construction are done by
     // the same document.
     // Note: don't use AccReorderEvent to avoid coalsecense and special reorder
     // events processing.
     docAcc->FireDelayedEvent(nsIAccessibleEvent::EVENT_REORDER,
                              ApplicationAcc());
 
     if (IPCAccessibilityActive()) {
-      DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
-      docAcc->SetIPCDoc(ipcDoc);
-      nsCOMPtr<nsITabChild> tabChild =
-        do_GetInterface(aDocument->GetDocShell());
-    static_cast<TabChild*>(tabChild.get())->
-      SendPDocAccessibleConstructor(ipcDoc, nullptr, 0);
+      nsIDocShell* docShell = aDocument->GetDocShell();
+      if (docShell) {
+        nsCOMPtr<nsITabChild> tabChild = do_GetInterface(docShell);
+
+        // XXX We may need to handle the case that we don't have a tab child
+        // differently.  It may be that this will cause us to fail to notify
+        // the parent process about important accessible documents.
+        if (tabChild) {
+          DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
+          docAcc->SetIPCDoc(ipcDoc);
+          static_cast<TabChild*>(tabChild.get())->
+            SendPDocAccessibleConstructor(ipcDoc, nullptr, 0);
+        }
+      }
     }
   } else {
     parentDocAcc->BindChildDocument(docAcc);
   }
 
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eDocCreate)) {
     logging::DocCreate("document creation finished", aDocument);
@@ -475,81 +525,39 @@ DocManager::CreateDocOrRootAccessible(ns
 
   AddListeners(aDocument, isRootDoc);
   return docAcc;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocManager static
 
-PLDHashOperator
-DocManager::GetFirstEntryInDocCache(const nsIDocument* aKey,
-                                    DocAccessible* aDocAccessible,
-                                    void* aUserArg)
-{
-  NS_ASSERTION(aDocAccessible,
-               "No doc accessible for the object in doc accessible cache!");
-  *reinterpret_cast<DocAccessible**>(aUserArg) = aDocAccessible;
-
-  return PL_DHASH_STOP;
-}
-
 void
 DocManager::ClearDocCache()
 {
-  DocAccessible* docAcc = nullptr;
-  while (mDocAccessibleCache.EnumerateRead(GetFirstEntryInDocCache, static_cast<void*>(&docAcc))) {
-    if (docAcc)
+  // This unusual do-one-element-per-iterator approach is required because each
+  // DocAccessible is removed elsewhere upon its Shutdown() method being
+  // called, which invalidates the existing iterator.
+  while (mDocAccessibleCache.Count() > 0) {
+    auto iter = mDocAccessibleCache.Iter();
+    MOZ_ASSERT(!iter.Done());
+    DocAccessible* docAcc = iter.UserData();
+    NS_ASSERTION(docAcc,
+                 "No doc accessible for the object in doc accessible cache!");
+    if (docAcc) {
       docAcc->Shutdown();
+    }
   }
 }
 
-PLDHashOperator
-DocManager::SearchAccessibleInDocCache(const nsIDocument* aKey,
-                                       DocAccessible* aDocAccessible,
-                                       void* aUserArg)
-{
-  NS_ASSERTION(aDocAccessible,
-               "No doc accessible for the object in doc accessible cache!");
-
-  if (aDocAccessible) {
-    nsSearchAccessibleInCacheArg* arg =
-      static_cast<nsSearchAccessibleInCacheArg*>(aUserArg);
-    arg->mAccessible = aDocAccessible->GetAccessible(arg->mNode);
-    if (arg->mAccessible)
-      return PL_DHASH_STOP;
-  }
-
-  return PL_DHASH_NEXT;
-}
-
-#ifdef DEBUG
-PLDHashOperator
-DocManager::SearchIfDocIsRefreshing(const nsIDocument* aKey,
-                                    DocAccessible* aDocAccessible,
-                                    void* aUserArg)
-{
-  NS_ASSERTION(aDocAccessible,
-               "No doc accessible for the object in doc accessible cache!");
-
-  if (aDocAccessible && aDocAccessible->mNotificationController &&
-      aDocAccessible->mNotificationController->IsUpdating()) {
-    *(static_cast<bool*>(aUserArg)) = true;
-    return PL_DHASH_STOP;
-  }
-
-  return PL_DHASH_NEXT;
-}
-#endif
-
 void
 DocManager::RemoteDocAdded(DocAccessibleParent* aDoc)
 {
   if (!sRemoteDocuments) {
     sRemoteDocuments = new nsTArray<DocAccessibleParent*>;
     ClearOnShutdown(&sRemoteDocuments);
   }
 
   MOZ_ASSERT(!sRemoteDocuments->Contains(aDoc),
       "How did we already have the doc!");
   sRemoteDocuments->AppendElement(aDoc);
-  ProxyCreated(aDoc, 0);
+  ProxyCreated(aDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT);
 }
--- a/accessible/base/DocManager.h
+++ b/accessible/base/DocManager.h
@@ -82,16 +82,34 @@ public:
     MOZ_ASSERT(result, "Why didn't we find the document!");
   }
 
   /*
    * 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() { }
 
@@ -128,52 +146,29 @@ private:
   void RemoveListeners(nsIDocument* aDocument);
 
   /**
    * Create document or root accessible.
    */
   DocAccessible* CreateDocOrRootAccessible(nsIDocument* aDocument);
 
   /**
-   * Get first entry of the document accessible from cache.
-   */
-  static PLDHashOperator
-    GetFirstEntryInDocCache(const nsIDocument* aKey,
-                            DocAccessible* aDocAccessible,
-                            void* aUserArg);
-
-  /**
    * Clear the cache and shutdown the document accessibles.
    */
   void ClearDocCache();
 
-  struct nsSearchAccessibleInCacheArg
-  {
-    Accessible* mAccessible;
-    nsINode* mNode;
-  };
-
-  static PLDHashOperator
-    SearchAccessibleInDocCache(const nsIDocument* aKey,
-                               DocAccessible* aDocAccessible,
-                               void* aUserArg);
-
-#ifdef DEBUG
-  static PLDHashOperator
-    SearchIfDocIsRefreshing(const nsIDocument* aKey,
-                            DocAccessible* aDocAccessible, void* aUserArg);
-#endif
-
   typedef nsRefPtrHashtable<nsPtrHashKey<const nsIDocument>, DocAccessible>
     DocAccessibleHashtable;
   DocAccessibleHashtable mDocAccessibleCache;
 
   typedef nsRefPtrHashtable<nsPtrHashKey<const DocAccessible>, xpcAccessibleDocument>
     XPCDocumentHashtable;
   XPCDocumentHashtable mXPCDocumentCache;
+  static nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>, xpcAccessibleDocument>*
+    sRemoteXPCDocumentCache;
 
   /*
    * The list of remote top level documents.
    */
   static StaticAutoPtr<nsTArray<DocAccessibleParent*>> sRemoteDocuments;
 };
 
 /**
--- a/accessible/base/EventQueue.cpp
+++ b/accessible/base/EventQueue.cpp
@@ -56,17 +56,17 @@ EventQueue::PushEvent(AccEvent* aEvent)
     while (parent &&
            nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeIfReqRule)) {
       // Test possible name dependent parent.
       if (nsTextEquivUtils::HasNameRule(parent, eNameFromSubtreeRule)) {
         nsAutoString name;
         ENameValueFlag nameFlag = parent->Name(name);
         // If name is obtained from subtree, fire name change event.
         if (nameFlag == eNameFromSubtree) {
-          nsRefPtr<AccEvent> nameChangeEvent =
+          RefPtr<AccEvent> nameChangeEvent =
             new AccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, parent);
           PushEvent(nameChangeEvent);
         }
         break;
       }
       parent = parent->Parent();
     }
   }
@@ -243,22 +243,17 @@ EventQueue::CoalesceReorderEvents(AccEve
     if (!thisEvent->mAccessible->IsDoc() &&
         !thisEvent->mAccessible->IsInDocument()) {
       thisEvent->mEventRule = AccEvent::eDoNotEmit;
       continue;
     }
 
     // Coalesce earlier event of the same target.
     if (thisEvent->mAccessible == aTailEvent->mAccessible) {
-      if (thisEvent->mEventRule == AccEvent::eDoNotEmit) {
-        AccReorderEvent* tailReorder = downcast_accEvent(aTailEvent);
-        tailReorder->DoNotEmitAll();
-      } else {
-        thisEvent->mEventRule = AccEvent::eDoNotEmit;
-      }
+      thisEvent->mEventRule = AccEvent::eDoNotEmit;
 
       return;
     }
 
     // If tailEvent contains thisEvent
     // then
     //   if show or hide of tailEvent contains a grand parent of thisEvent
     //   then ignore thisEvent and its show and hide events
@@ -295,22 +290,26 @@ EventQueue::CoalesceReorderEvents(AccEve
     //   then assert
     //   otherwise ignore tailEvent but not its show and hide events
     Accessible* tailParent = aTailEvent->mAccessible;
     while (tailParent && tailParent != mDocument) {
       if (tailParent->Parent() == thisEvent->mAccessible) {
         AccReorderEvent* thisReorder = downcast_accEvent(thisEvent);
         AccReorderEvent* tailReorder = downcast_accEvent(aTailEvent);
         uint32_t eventType = thisReorder->IsShowHideEventTarget(tailParent);
-        if (eventType == nsIAccessibleEvent::EVENT_SHOW)
+        if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
           tailReorder->DoNotEmitAll();
-        else if (eventType == nsIAccessibleEvent::EVENT_HIDE)
+        }
+        else if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
           NS_ERROR("Accessible tree was modified after it was removed! Huh?");
-        else
+        }
+        else {
           aTailEvent->mEventRule = AccEvent::eDoNotEmit;
+          mEvents[index].swap(mEvents[count - 1]);
+        }
 
         return;
       }
 
       tailParent = tailParent->Parent();
     }
 
   } // for (index)
@@ -475,62 +474,24 @@ EventQueue::CreateTextChangeEventFor(Acc
   if (text.IsEmpty())
     return;
 
   aEvent->mTextChangeEvent =
     new AccTextChangeEvent(textAccessible, offset, text, aEvent->IsShow(),
                            aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
 }
 
-void
-EventQueue::SendIPCEvent(AccEvent* aEvent) const
-{
-  DocAccessibleChild* ipcDoc = mDocument->IPCDoc();
-  uint64_t id = aEvent->GetAccessible()->IsDoc() ? 0 :
-    reinterpret_cast<uintptr_t>(aEvent->GetAccessible());
-
-  switch(aEvent->GetEventType()) {
-    case nsIAccessibleEvent::EVENT_SHOW:
-      ipcDoc->ShowEvent(downcast_accEvent(aEvent));
-      break;
-
-    case nsIAccessibleEvent::EVENT_HIDE:
-      ipcDoc->SendHideEvent(id);
-      break;
-
-    case nsIAccessibleEvent::EVENT_REORDER:
-      // reorder events on the application acc aren't necessary to tell the parent
-      // about new top level documents.
-      if (!aEvent->GetAccessible()->IsApplication())
-        ipcDoc->SendEvent(id, aEvent->GetEventType());
-      break;
-    case nsIAccessibleEvent::EVENT_STATE_CHANGE: {
-      AccStateChangeEvent* event = downcast_accEvent(aEvent);
-      ipcDoc->SendStateChangeEvent(id, event->GetState(),
-                                   event->IsStateEnabled());
-      break;
-    }
-    case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: {
-                                                       AccCaretMoveEvent* event = downcast_accEvent(aEvent);
-                                                       ipcDoc->SendEvent(id, event->GetCaretOffset());
-                                                       break;
-                                                     }
-    default:
-      ipcDoc->SendEvent(id, aEvent->GetEventType());
-  }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // EventQueue: event queue
 
 void
 EventQueue::ProcessEventQueue()
 {
   // Process only currently queued events.
-  nsTArray<nsRefPtr<AccEvent> > events;
+  nsTArray<RefPtr<AccEvent> > events;
   events.SwapElements(mEvents);
 
   uint32_t eventCount = events.Length();
 #ifdef A11Y_LOG
   if (eventCount > 0 && logging::IsEnabled(logging::eEvents)) {
     logging::MsgBegin("EVENTS", "events processing");
     logging::Address("document", mDocument);
     logging::MsgEnd();
@@ -584,18 +545,17 @@ EventQueue::ProcessEventQueue()
       // Fire text change events.
       AccMutationEvent* mutationEvent = downcast_accEvent(event);
       if (mutationEvent) {
         if (mutationEvent->mTextChangeEvent)
           nsEventShell::FireEvent(mutationEvent->mTextChangeEvent);
       }
     }
 
-    if (event->mEventType == nsIAccessibleEvent::EVENT_HIDE)
+    AccHideEvent* hideEvent = downcast_accEvent(event);
+    if (hideEvent && hideEvent->NeedsShutdown()) {
       mDocument->ShutdownChildrenInSubtree(event->mAccessible);
+    }
 
     if (!mDocument)
       return;
-
-    if (IPCAccessibilityActive())
-      SendIPCEvent(event);
   }
 }
--- a/accessible/base/EventQueue.h
+++ b/accessible/base/EventQueue.h
@@ -49,21 +49,16 @@ private:
   /**
    * Coalesce two selection change events within the same select control.
    */
   void CoalesceSelChangeEvents(AccSelChangeEvent* aTailEvent,
                                AccSelChangeEvent* aThisEvent,
                                uint32_t aThisIndex);
 
   /**
-   * Notify the parent process of events being fired by this event queue.
-   */
-  void SendIPCEvent(AccEvent* aEvent) const;
-
-  /**
    * Coalesce text change events caused by sibling hide events.
    */
   void CoalesceTextChangeEventsFor(AccHideEvent* aTailEvent,
                                    AccHideEvent* aThisEvent);
   void CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
                                    AccShowEvent* aThisEvent);
 
   /**
@@ -76,18 +71,18 @@ 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<nsRefPtr<AccEvent> > mEvents;
+  nsTArray<RefPtr<AccEvent> > mEvents;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_EventQueue_h_
--- a/accessible/base/Filters.cpp
+++ b/accessible/base/Filters.cpp
@@ -42,20 +42,17 @@ filters::GetRow(Accessible* aAccessible)
     return eSkip;
 
   return eSkipSubtree;
 }
 
 uint32_t
 filters::GetCell(Accessible* aAccessible)
 {
-  a11y::role role = aAccessible->Role();
-  return role == roles::CELL || role == roles::GRID_CELL ||
-         role == roles::ROWHEADER || role == roles::COLUMNHEADER ?
-    eMatch : eSkipSubtree;
+  return aAccessible->IsTableCell() ? eMatch : eSkipSubtree;
 }
 
 uint32_t
 filters::GetEmbeddedObject(Accessible* aAccessible)
 {
   return nsAccUtils::IsEmbeddedObject(aAccessible) ?
     eMatch | eSkipSubtree : eSkipSubtree;
 }
--- a/accessible/base/FocusManager.cpp
+++ b/accessible/base/FocusManager.cpp
@@ -213,17 +213,17 @@ FocusManager::ForceFocusEvent()
 }
 
 void
 FocusManager::DispatchFocusEvent(DocAccessible* aDocument,
                                  Accessible* aTarget)
 {
   NS_PRECONDITION(aDocument, "No document for focused accessible!");
   if (aDocument) {
-    nsRefPtr<AccEvent> event =
+    RefPtr<AccEvent> event =
       new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, aTarget,
                    eAutoDetect, AccEvent::eCoalesceOfSameType);
     aDocument->FireDelayedEvent(event);
 
 #ifdef A11Y_LOG
     if (logging::IsEnabled(logging::eFocus))
       logging::FocusDispatched(aTarget);
 #endif
@@ -294,67 +294,52 @@ FocusManager::ProcessFocusEvent(AccEvent
       mActiveItem = activeItem;
       target = activeItem;
     }
   }
 
   // Fire menu start/end events for ARIA menus.
   if (target->IsARIARole(nsGkAtoms::menuitem)) {
     // The focus was moved into menu.
-    bool tryOwnsParent = true;
     Accessible* ARIAMenubar = nullptr;
-    Accessible* child = target;
-    Accessible* parent = child->Parent();
-    while (parent) {
-      nsRoleMapEntry* roleMap = parent->ARIARoleMap();
-      if (roleMap) {
-        if (roleMap->Is(nsGkAtoms::menubar)) {
-          ARIAMenubar = parent;
-          break;
-        }
-
-        // Go up in the parent chain of the menu hierarchy.
-        if (roleMap->Is(nsGkAtoms::menuitem) || roleMap->Is(nsGkAtoms::menu)) {
-          child = parent;
-          parent = child->Parent();
-          tryOwnsParent = true;
-          continue;
-        }
+    for (Accessible* parent = target->Parent(); parent; parent = parent->Parent()) {
+      if (parent->IsARIARole(nsGkAtoms::menubar)) {
+        ARIAMenubar = parent;
+        break;
       }
 
-      // If no required context role then check aria-owns relation.
-      if (!tryOwnsParent)
+      // Go up in the parent chain of the menu hierarchy.
+      if (!parent->IsARIARole(nsGkAtoms::menuitem) &&
+          !parent->IsARIARole(nsGkAtoms::menu)) {
         break;
-
-      parent = ARIAOwnedByIterator(child).Next();
-      tryOwnsParent = false;
+      }
     }
 
     if (ARIAMenubar != mActiveARIAMenubar) {
       // Leaving ARIA menu. Fire menu_end event on current menubar.
       if (mActiveARIAMenubar) {
-        nsRefPtr<AccEvent> menuEndEvent =
+        RefPtr<AccEvent> menuEndEvent =
           new AccEvent(nsIAccessibleEvent::EVENT_MENU_END, mActiveARIAMenubar,
                        aEvent->FromUserInput());
         nsEventShell::FireEvent(menuEndEvent);
       }
 
       mActiveARIAMenubar = ARIAMenubar;
 
       // Entering ARIA menu. Fire menu_start event.
       if (mActiveARIAMenubar) {
-        nsRefPtr<AccEvent> menuStartEvent =
+        RefPtr<AccEvent> menuStartEvent =
           new AccEvent(nsIAccessibleEvent::EVENT_MENU_START,
                        mActiveARIAMenubar, aEvent->FromUserInput());
         nsEventShell::FireEvent(menuStartEvent);
       }
     }
   } else if (mActiveARIAMenubar) {
     // Focus left a menu. Fire menu_end event.
-    nsRefPtr<AccEvent> menuEndEvent =
+    RefPtr<AccEvent> menuEndEvent =
       new AccEvent(nsIAccessibleEvent::EVENT_MENU_END, mActiveARIAMenubar,
                    aEvent->FromUserInput());
     nsEventShell::FireEvent(menuEndEvent);
 
     mActiveARIAMenubar = nullptr;
   }
 
 #ifdef A11Y_LOG
@@ -362,17 +347,17 @@ FocusManager::ProcessFocusEvent(AccEvent
     logging::FocusNotificationTarget("fire focus event", "Target", target);
 #endif
 
   // Reset cached caret value. The cache will be updated upon processing the
   // next caret move event. This ensures that we will return the correct caret
   // offset before the caret move event is handled.
   SelectionMgr()->ResetCaretOffset();
 
-  nsRefPtr<AccEvent> focusEvent =
+  RefPtr<AccEvent> focusEvent =
     new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, target, aEvent->FromUserInput());
   nsEventShell::FireEvent(focusEvent);
 
   // Fire scrolling_start event when the document receives the focus if it has
   // an anchor jump. If an accessible within the document receive the focus
   // then null out the anchor jump because it no longer applies.
   DocAccessible* targetDocument = target->Document();
   Accessible* anchorJump = targetDocument->AnchorJump();
@@ -399,17 +384,17 @@ FocusManager::FocusedDOMNode() const
   if (focusedElm) {
     if (EventStateManager::IsRemoteTarget(focusedElm)) {
       return nullptr;
     }
     return focusedElm;
   }
 
   // Otherwise the focus can be on DOM document.
-  nsPIDOMWindow* focusedWnd = DOMFocusManager->GetFocusedWindow();
+  nsPIDOMWindowOuter* focusedWnd = DOMFocusManager->GetFocusedWindow();
   return focusedWnd ? focusedWnd->GetExtantDoc() : nullptr;
 }
 
 nsIDocument*
 FocusManager::FocusedDOMDocument() const
 {
   nsINode* focusedNode = FocusedDOMNode();
   return focusedNode ? focusedNode->OwnerDoc() : nullptr;
--- a/accessible/base/FocusManager.h
+++ b/accessible/base/FocusManager.h
@@ -119,16 +119,16 @@ private:
   nsINode* FocusedDOMNode() const;
 
   /**
    * Return DOM document having DOM focus.
    */
   nsIDocument* FocusedDOMDocument() const;
 
 private:
-  nsRefPtr<Accessible> mActiveItem;
-  nsRefPtr<Accessible> mActiveARIAMenubar;
+  RefPtr<Accessible> mActiveItem;
+  RefPtr<Accessible> mActiveARIAMenubar;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/base/Logging.cpp
+++ b/accessible/base/Logging.cpp
@@ -40,24 +40,26 @@ struct ModuleRep {
 static ModuleRep sModuleMap[] = {
   { "docload", logging::eDocLoad },
   { "doccreate", logging::eDocCreate },
   { "docdestroy", logging::eDocDestroy },
   { "doclifecycle", logging::eDocLifeCycle },
 
   { "events", logging::eEvents },
   { "platforms", logging::ePlatforms },
-  { "stack", logging::eStack },
   { "text", logging::eText },
   { "tree", logging::eTree },
 
   { "DOMEvents", logging::eDOMEvents },
   { "focus", logging::eFocus },
   { "selection", logging::eSelection },
-  { "notifications", logging::eNotifications }
+  { "notifications", logging::eNotifications },
+
+  { "stack", logging::eStack },
+  { "verbose", logging::eVerbose }
 };
 
 static void
 EnableLogging(const char* aModulesStr)
 {
   sModules = 0;
   if (!aModulesStr)
     return;
@@ -162,18 +164,22 @@ LogDocState(nsIDocument* aDocumentNode)
 
   printf("doc state: %s", docState);
   printf(", %sinitial", aDocumentNode->IsInitialDocument() ? "" : "not ");
   printf(", %sshowing", aDocumentNode->IsShowing() ? "" : "not ");
   printf(", %svisible", aDocumentNode->IsVisible() ? "" : "not ");
   printf(", %svisible considering ancestors", aDocumentNode->IsVisibleConsideringAncestors() ? "" : "not ");
   printf(", %sactive", aDocumentNode->IsActive() ? "" : "not ");
   printf(", %sresource", aDocumentNode->IsResourceDoc() ? "" : "not ");
-  printf(", has %srole content",
-         nsCoreUtils::GetRoleContent(aDocumentNode) ? "" : "no ");
+
+  dom::Element* rootEl = aDocumentNode->GetBodyElement();
+  if (!rootEl) {
+    rootEl = aDocumentNode->GetRootElement();
+  }
+  printf(", has %srole content", rootEl ? "" : "no ");
 }
 
 static void
 LogPresShell(nsIDocument* aDocumentNode)
 {
   nsIPresShell* ps = aDocumentNode->GetShell();
   printf("presshell: %p", static_cast<void*>(ps));
 
@@ -387,19 +393,19 @@ static const char* sDocEventTitle = "DOC
 static const char* sFocusTitle = "FOCUS";
 
 void
 logging::DocLoad(const char* aMsg, nsIWebProgress* aWebProgress,
                  nsIRequest* aRequest, uint32_t aStateFlags)
 {
   MsgBegin(sDocLoadTitle, aMsg);
 
-  nsCOMPtr<nsIDOMWindow> DOMWindow;
+  nsCOMPtr<mozIDOMWindowProxy> DOMWindow;
   aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow));
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(DOMWindow);
+  nsPIDOMWindowOuter* window = nsPIDOMWindowOuter::From(DOMWindow);
   if (!window) {
     MsgEnd();
     return;
   }
 
   nsCOMPtr<nsIDocument> documentNode = window->GetDoc();
   if (!documentNode) {
     MsgEnd();
@@ -602,16 +608,71 @@ logging::SelChange(nsISelection* aSelect
   bool isIgnored = !aDocument || !aDocument->IsContentLoaded();
   printf("\nSelection changed, selection type: %s, notification %s, reason: %d\n",
          strType, (isIgnored ? "ignored" : "pending"), aReason);
 
   Stack();
 }
 
 void
+logging::TreeInfo(const char* aMsg, uint32_t aExtraFlags, ...)
+{
+  if (IsEnabledAll(logging::eTree | aExtraFlags)) {
+    MsgBegin("TREE", aMsg);
+
+    va_list vl;
+    va_start(vl, aExtraFlags);
+    const char* descr = nullptr;
+    while ((descr = va_arg(vl, const char*))) {
+      AccessibleInfo(descr, va_arg(vl, Accessible*));
+    }
+    va_end(vl);
+
+    MsgEnd();
+
+    if (aExtraFlags & eStack) {
+      Stack();
+    }
+  }
+}
+
+void
+logging::TreeInfo(const char* aMsg, uint32_t aExtraFlags,
+                  const char* aMsg1, Accessible* aAcc,
+                  const char* aMsg2, nsINode* aNode)
+{
+  if (IsEnabledAll(logging::eTree | logging::eVerbose)) {
+    MsgBegin("TREE", aMsg);
+    AccessibleInfo(aMsg1, aAcc);
+    Accessible* acc = aAcc->Document()->GetAccessible(aNode);
+    if (acc) {
+      AccessibleInfo(aMsg2, acc);
+    }
+    else {
+      Node(aMsg2, aNode);
+    }
+    MsgEnd();
+  }
+}
+
+
+void
+logging::TreeInfo(const char* aMsg, uint32_t aExtraFlags, Accessible* aParent)
+{
+  if (IsEnabledAll(logging::eTree | aExtraFlags)) {
+    MsgBegin("TREE", aMsg);
+    AccessibleInfo("container", aParent);
+    for (uint32_t idx = 0; idx < aParent->ChildCount(); idx++) {
+      AccessibleInfo("child", aParent->GetChildAt(idx));
+    }
+    MsgEnd();
+  }
+}
+
+void
 logging::MsgBegin(const char* aTitle, const char* aMsgText, ...)
 {
   printf("\nA11Y %s: ", aTitle);
 
   va_list argptr;
   va_start(argptr, aMsgText);
   vprintf(aMsgText, argptr);
   va_end(argptr);
@@ -732,16 +793,72 @@ logging::Document(DocAccessible* aDocume
          static_cast<void*>(aDocument->DocumentNode()));
 
   printf("    Document ");
   LogDocURI(aDocument->DocumentNode());
   printf("\n");
 }
 
 void
+logging::AccessibleInfo(const char* aDescr, Accessible* aAccessible)
+{
+  printf("    %s: %p; ", aDescr, static_cast<void*>(aAccessible));
+  if (!aAccessible) {
+    printf("\n");
+    return;
+  }
+  if (aAccessible->IsDefunct()) {
+    printf("defunct\n");
+    return;
+  }
+  if (!aAccessible->Document() || aAccessible->Document()->IsDefunct()) {
+    printf("document is shutting down, no info\n");
+    return;
+  }
+
+  nsAutoString role;
+  GetAccService()->GetStringRole(aAccessible->Role(), role);
+  printf("role: %s", NS_ConvertUTF16toUTF8(role).get());
+
+  nsAutoString name;
+  aAccessible->Name(name);
+  if (!name.IsEmpty()) {
+    printf(", name: '%s'", NS_ConvertUTF16toUTF8(name).get());
+  }
+
+  printf(", idx: %d", aAccessible->IndexInParent());
+
+  nsINode* node = aAccessible->GetNode();
+  if (!node) {
+    printf(", node: null\n");
+  }
+  else if (node->IsNodeOfType(nsINode::eDOCUMENT)) {
+    printf(", document node: %p\n", static_cast<void*>(node));
+  }
+  else if (node->IsNodeOfType(nsINode::eTEXT)) {
+    printf(", text node: %p\n", static_cast<void*>(node));
+  }
+  else if (node->IsElement()) {
+    dom::Element* el = node->AsElement();
+
+    nsAutoCString tag;
+    el->NodeInfo()->NameAtom()->ToUTF8String(tag);
+
+    nsIAtom* idAtom = el->GetID();
+    nsAutoCString id;
+    if (idAtom) {
+      idAtom->ToUTF8String(id);
+    }
+
+    printf(", element node: %p, %s@id='%s'\n",
+           static_cast<void*>(el), tag.get(), id.get());
+  }
+}
+
+void
 logging::AccessibleNNode(const char* aDescr, Accessible* aAccessible)
 {
   printf("    %s: %p; ", aDescr, static_cast<void*>(aAccessible));
   if (!aAccessible)
     return;
 
   nsAutoString role;
   GetAccService()->GetStringRole(aAccessible->Role(), role);
@@ -810,16 +927,22 @@ logging::Stack()
 
 bool
 logging::IsEnabled(uint32_t aModules)
 {
   return sModules & aModules;
 }
 
 bool
+logging::IsEnabledAll(uint32_t aModules)
+{
+  return (sModules & aModules) == aModules;
+}
+
+bool
 logging::IsEnabled(const nsAString& aModuleStr)
 {
   for (unsigned int idx = 0; idx < ArrayLength(sModuleMap); idx++) {
     if (aModuleStr.EqualsASCII(sModuleMap[idx].mStr))
       return sModules & sModuleMap[idx].mModule;
   }
 
   return false;
--- a/accessible/base/Logging.h
+++ b/accessible/base/Logging.h
@@ -30,32 +30,40 @@ namespace logging {
 enum EModules {
   eDocLoad = 1 << 0,
   eDocCreate = 1 << 1,
   eDocDestroy = 1 << 2,
   eDocLifeCycle = eDocLoad | eDocCreate | eDocDestroy,
 
   eEvents = 1 << 3,
   ePlatforms = 1 << 4,
-  eStack = 1 << 5,
-  eText = 1 << 6,
-  eTree = 1 << 7,
+  eText = 1 << 5,
+  eTree = 1 << 6,
 
-  eDOMEvents = 1 << 8,
-  eFocus = 1 << 9,
-  eSelection = 1 << 10,
-  eNotifications = eDOMEvents | eSelection | eFocus
+  eDOMEvents = 1 << 7,
+  eFocus = 1 << 8,
+  eSelection = 1 << 9,
+  eNotifications = eDOMEvents | eSelection | eFocus,
+
+  // extras
+  eStack = 1 << 10,
+  eVerbose = 1 << 11
 };
 
 /**
  * Return true if any of the given modules is logged.
  */
 bool IsEnabled(uint32_t aModules);
 
 /**
+ * Return true if all of the given modules are logged.
+ */
+bool IsEnabledAll(uint32_t aModules);
+
+/**
  * Return true if the given module is logged.
  */
 bool IsEnabled(const nsAString& aModules);
 
 /**
  * Log the document loading progress.
  */
 void DocLoad(const char* aMsg, nsIWebProgress* aWebProgress,
@@ -117,16 +125,25 @@ void FocusDispatched(Accessible* aTarget
 
 /**
  * Log the selection change.
  */
 void SelChange(nsISelection* aSelection, DocAccessible* aDocument,
                int16_t aReason);
 
 /**
+ * Log the given accessible elements info.
+ */
+void TreeInfo(const char* aMsg, uint32_t aExtraFlags, ...);
+void TreeInfo(const char* aMsg, uint32_t aExtraFlags,
+              const char* aMsg1, Accessible* aAcc,
+              const char* aMsg2, nsINode* aNode);
+void TreeInfo(const char* aMsg, uint32_t aExtraFlags, Accessible* aParent);
+
+/**
  * Log the message ('title: text' format) on new line. Print the start and end
  * boundaries of the message body designated by '{' and '}' (2 spaces indent for
  * body).
  */
 void MsgBegin(const char* aTitle, const char* aMsgText, ...);
 void MsgEnd();
 
 /**
@@ -159,16 +176,17 @@ void Node(const char* aDescr, nsINode* a
 /**
  * Log the document accessible info as message entry.
  */
 void Document(DocAccessible* aDocument);
 
 /**
  * Log the accessible and its DOM node as a message entry.
  */
+void AccessibleInfo(const char* aDescr, Accessible* aAccessible);
 void AccessibleNNode(const char* aDescr, Accessible* aAccessible);
 void AccessibleNNode(const char* aDescr, nsINode* aNode);
 
 /**
  * Log the DOM event.
  */
 void DOMEvent(const char* aDescr, nsINode* aOrigTarget,
               const nsAString& aEventType);
@@ -184,14 +202,15 @@ void Stack();
 void Enable(const nsAFlatCString& aModules);
 
 /**
  * Enable logging of modules specified by A11YLOG environment variable,
  * all other modules aren't logged.
  */
 void CheckEnv();
 
-} // namespace logs
+} // namespace logging
+
 } // namespace a11y
 } // namespace mozilla
 
 #endif
 
--- a/accessible/base/NotificationController.cpp
+++ b/accessible/base/NotificationController.cpp
@@ -47,18 +47,28 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(Notificat
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(NotificationController)
   if (tmp->mDocument)
     tmp->Shutdown();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(NotificationController)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHangingChildDocuments)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContentInsertions)
+  for (auto it = tmp->mContentInsertions.ConstIter(); !it.Done(); it.Next()) {
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mContentInsertions key");
+    cb.NoteXPCOMChild(it.Key());
+    nsTArray<nsCOMPtr<nsIContent>>* list = it.UserData();
+    for (uint32_t i = 0; i < list->Length(); i++) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
+                                         "mContentInsertions value item");
+      cb.NoteXPCOMChild(list->ElementAt(i));
+    }
+  }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvents)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelocations)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(NotificationController, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(NotificationController, Release)
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: public
 
@@ -81,69 +91,84 @@ NotificationController::Shutdown()
 
   mDocument = nullptr;
   mPresShell = nullptr;
 
   mTextHash.Clear();
   mContentInsertions.Clear();
   mNotifications.Clear();
   mEvents.Clear();
+  mRelocations.Clear();
 }
 
 void
 NotificationController::ScheduleChildDocBinding(DocAccessible* aDocument)
 {
   // Schedule child document binding to the tree.
   mHangingChildDocuments.AppendElement(aDocument);
   ScheduleProcessing();
 }
 
 void
 NotificationController::ScheduleContentInsertion(Accessible* aContainer,
                                                  nsIContent* aStartChildNode,
                                                  nsIContent* aEndChildNode)
 {
-  nsRefPtr<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();
   }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// NotificationCollector: protected
-
 void
 NotificationController::ScheduleProcessing()
 {
   // If notification flush isn't planed yet start notification flush
   // asynchronously (after style and layout).
   if (mObservingState == eNotObservingRefresh) {
     if (mPresShell->AddRefreshObserver(this, Flush_Display))
       mObservingState = eRefreshObserving;
   }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// NotificationCollector: protected
+
 bool
 NotificationController::IsUpdatePending()
 {
   return mPresShell->IsLayoutFlushObserver() ||
     mObservingState == eRefreshProcessingForUpdate ||
-    mContentInsertions.Length() != 0 || mNotifications.Length() != 0 ||
+    mContentInsertions.Count() != 0 || mNotifications.Length() != 0 ||
     mTextHash.Count() != 0 ||
     !mDocument->HasLoadState(DocAccessible::eTreeConstructed);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: private
 
 void
 NotificationController::WillRefresh(mozilla::TimeStamp aTime)
 {
+  PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
   Telemetry::AutoTimer<Telemetry::A11Y_UPDATE_TIME> updateTimer;
 
   // If the document accessible that notification collector was created for is
   // now shut down, don't process notifications anymore.
   NS_ASSERTION(mDocument,
                "The document was shut down while refresh observer is attached!");
   if (!mDocument)
     return;
@@ -170,17 +195,17 @@ NotificationController::WillRefresh(mozi
       logging::MsgBegin("TREE", "initial tree created");
       logging::Address("document", mDocument);
       logging::MsgEnd();
     }
 #endif
 
     mDocument->DoInitialUpdate();
 
-    NS_ASSERTION(mContentInsertions.Length() == 0,
+    NS_ASSERTION(mContentInsertions.Count() == 0,
                  "Pending content insertions while initial accessible tree isn't created!");
   }
 
   // Initialize scroll support if needed.
   if (!(mDocument->mDocFlags & DocAccessible::eScrollInitialized))
     mDocument->AddScrollListener();
 
   // Process content inserted notifications to update the tree. Process other
@@ -188,33 +213,114 @@ 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<nsRefPtr<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.
-  mTextHash.EnumerateEntries(TextEnumerator, mDocument);
+  for (auto iter = mTextHash.Iter(); !iter.Done(); iter.Next()) {
+    nsCOMPtrHashKey<nsIContent>* entry = iter.Get();
+    nsIContent* textNode = entry->GetKey();
+    Accessible* textAcc = mDocument->GetAccessible(textNode);
+
+    // If the text node is not in tree or doesn't have frame then this case should
+    // have been handled already by content removal notifications.
+    nsINode* containerNode = textNode->GetParentNode();
+    if (!containerNode) {
+      NS_ASSERTION(!textAcc,
+                   "Text node was removed but accessible is kept alive!");
+      continue;
+    }
+
+    nsIFrame* textFrame = textNode->GetPrimaryFrame();
+    if (!textFrame) {
+      NS_ASSERTION(!textAcc,
+                   "Text node isn't rendered but accessible is kept alive!");
+      continue;
+    }
+
+    nsIContent* containerElm = containerNode->IsElement() ?
+      containerNode->AsElement() : nullptr;
+
+    nsIFrame::RenderedText text = textFrame->GetRenderedText(0,
+        UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
+        nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
+
+    // Remove text accessible if rendered text is empty.
+    if (textAcc) {
+      if (text.mString.IsEmpty()) {
+  #ifdef A11Y_LOG
+        if (logging::IsEnabled(logging::eTree | logging::eText)) {
+          logging::MsgBegin("TREE", "text node lost its content");
+          logging::Node("container", containerElm);
+          logging::Node("content", textNode);
+          logging::MsgEnd();
+        }
+  #endif
+
+        mDocument->ContentRemoved(containerElm, textNode);
+        continue;
+      }
+
+      // Update text of the accessible and fire text change events.
+  #ifdef A11Y_LOG
+      if (logging::IsEnabled(logging::eText)) {
+        logging::MsgBegin("TEXT", "text may be changed");
+        logging::Node("container", containerElm);
+        logging::Node("content", textNode);
+        logging::MsgEntry("old text '%s'",
+                          NS_ConvertUTF16toUTF8(textAcc->AsTextLeaf()->Text()).get());
+        logging::MsgEntry("new text: '%s'",
+                          NS_ConvertUTF16toUTF8(text.mString).get());
+        logging::MsgEnd();
+      }
+  #endif
+
+      TextUpdater::Run(mDocument, textAcc->AsTextLeaf(), text.mString);
+      continue;
+    }
+
+    // Append an accessible if rendered text is not empty.
+    if (!text.mString.IsEmpty()) {
+  #ifdef A11Y_LOG
+      if (logging::IsEnabled(logging::eTree | logging::eText)) {
+        logging::MsgBegin("TREE", "text node gains new content");
+        logging::Node("container", containerElm);
+        logging::Node("content", textNode);
+        logging::MsgEnd();
+      }
+  #endif
+
+      // Make sure the text node is in accessible document still.
+      Accessible* container = mDocument->GetAccessibleOrContainer(containerNode);
+      NS_ASSERTION(container,
+                   "Text node having rendered text hasn't accessible document!");
+      if (container) {
+        nsTArray<nsCOMPtr<nsIContent> > insertedContents;
+        insertedContents.AppendElement(textNode);
+        mDocument->ProcessContentInserted(container, &insertedContents);
+      }
+    }
+  }
   mTextHash.Clear();
 
   // Bind hanging child documents.
   uint32_t hangingDocCnt = mHangingChildDocuments.Length();
-  nsTArray<nsRefPtr<DocAccessible>> newChildDocs;
+  nsTArray<RefPtr<DocAccessible>> newChildDocs;
   for (uint32_t idx = 0; idx < hangingDocCnt; idx++) {
     DocAccessible* childDoc = mHangingChildDocuments[idx];
     if (childDoc->IsDefunct())
       continue;
 
     nsIContent* ownerContent = mDocument->DocumentNode()->
       FindContentForSubDocument(childDoc->DocumentNode());
     if (ownerContent) {
@@ -250,30 +356,40 @@ NotificationController::WillRefresh(mozi
     if (childDocIdx == childDocCnt) {
       mDocument->ProcessLoad();
       if (!mDocument)
         return;
     }
   }
 
   // Process only currently queued generic notifications.
-  nsTArray < nsRefPtr<Notification> > notifications;
+  nsTArray < RefPtr<Notification> > notifications;
   notifications.SwapElements(mNotifications);
 
   uint32_t notificationCount = notifications.Length();
   for (uint32_t idx = 0; idx < notificationCount; idx++) {
     notifications[idx]->Process();
     if (!mDocument)
       return;
   }
 
   // Process invalidation list of the document after all accessible tree
   // modification are done.
   mDocument->ProcessInvalidationList();
 
+  // We cannot rely on DOM tree to keep aria-owns relations updated. Make
+  // a validation to remove dead links.
+  mDocument->ValidateARIAOwned();
+
+  // Process relocation list.
+  for (uint32_t idx = 0; idx < mRelocations.Length(); idx++) {
+    mDocument->DoARIAOwnsRelocation(mRelocations[idx]);
+  }
+  mRelocations.Clear();
+
   // If a generic notification occurs after this point then we may be allowed to
   // process it synchronously.  However we do not want to reenter if fireing
   // events causes script to run.
   mObservingState = eRefreshProcessing;
 
   ProcessEventQueue();
 
   if (IPCAccessibilityActive()) {
@@ -289,170 +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;
   }
 }
-
-////////////////////////////////////////////////////////////////////////////////
-// Notification controller: text leaf accessible text update
-
-PLDHashOperator
-NotificationController::TextEnumerator(nsCOMPtrHashKey<nsIContent>* aEntry,
-                                       void* aUserArg)
-{
-  DocAccessible* document = static_cast<DocAccessible*>(aUserArg);
-  nsIContent* textNode = aEntry->GetKey();
-  Accessible* textAcc = document->GetAccessible(textNode);
-
-  // If the text node is not in tree or doesn't have frame then this case should
-  // have been handled already by content removal notifications.
-  nsINode* containerNode = textNode->GetParentNode();
-  if (!containerNode) {
-    NS_ASSERTION(!textAcc,
-                 "Text node was removed but accessible is kept alive!");
-    return PL_DHASH_NEXT;
-  }
-
-  nsIFrame* textFrame = textNode->GetPrimaryFrame();
-  if (!textFrame) {
-    NS_ASSERTION(!textAcc,
-                 "Text node isn't rendered but accessible is kept alive!");
-    return PL_DHASH_NEXT;
-  }
-
-  nsIContent* containerElm = containerNode->IsElement() ?
-    containerNode->AsElement() : nullptr;
-
-  nsAutoString text;
-  textFrame->GetRenderedText(&text);
-
-  // Remove text accessible if rendered text is empty.
-  if (textAcc) {
-    if (text.IsEmpty()) {
-#ifdef A11Y_LOG
-      if (logging::IsEnabled(logging::eTree | logging::eText)) {
-        logging::MsgBegin("TREE", "text node lost its content");
-        logging::Node("container", containerElm);
-        logging::Node("content", textNode);
-        logging::MsgEnd();
-      }
-#endif
-
-      document->ContentRemoved(containerElm, textNode);
-      return PL_DHASH_NEXT;
-    }
-
-    // Update text of the accessible and fire text change events.
-#ifdef A11Y_LOG
-    if (logging::IsEnabled(logging::eText)) {
-      logging::MsgBegin("TEXT", "text may be changed");
-      logging::Node("container", containerElm);
-      logging::Node("content", textNode);
-      logging::MsgEntry("old text '%s'",
-                        NS_ConvertUTF16toUTF8(textAcc->AsTextLeaf()->Text()).get());
-      logging::MsgEntry("new text: '%s'",
-                        NS_ConvertUTF16toUTF8(text).get());
-      logging::MsgEnd();
-    }
-#endif
-
-    TextUpdater::Run(document, textAcc->AsTextLeaf(), text);
-    return PL_DHASH_NEXT;
-  }
-
-  // Append an accessible if rendered text is not empty.
-  if (!text.IsEmpty()) {
-#ifdef A11Y_LOG
-    if (logging::IsEnabled(logging::eTree | logging::eText)) {
-      logging::MsgBegin("TREE", "text node gains new content");
-      logging::Node("container", containerElm);
-      logging::Node("content", textNode);
-      logging::MsgEnd();
-    }
-#endif
-
-    // Make sure the text node is in accessible document still.
-    Accessible* container = document->GetAccessibleOrContainer(containerNode);
-    NS_ASSERTION(container,
-                 "Text node having rendered text hasn't accessible document!");
-    if (container) {
-      nsTArray<nsCOMPtr<nsIContent> > insertedContents;
-      insertedContents.AppendElement(textNode);
-      document->ProcessContentInserted(container, &insertedContents);
-    }
-  }
-
-  return PL_DHASH_NEXT;
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-// 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
@@ -3,16 +3,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_NotificationController_h_
 #define mozilla_a11y_NotificationController_h_
 
 #include "EventQueue.h"
 
+#include "mozilla/IndexSequence.h"
+#include "mozilla/Tuple.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsRefreshDriver.h"
 
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
 
 namespace mozilla {
@@ -49,42 +51,42 @@ private:
 
 /**
  * Template class for generic notification.
  *
  * @note  Instance is kept as a weak ref, the caller must guarantee it exists
  *        longer than the document accessible owning the notification controller
  *        that this notification is processed by.
  */
-template<class Class, class Arg>
+template<class Class, class ... Args>
 class TNotification : public Notification
 {
 public:
-  typedef void (Class::*Callback)(Arg*);
+  typedef void (Class::*Callback)(Args* ...);
 
-  TNotification(Class* aInstance, Callback aCallback, Arg* aArg) :
-    mInstance(aInstance), mCallback(aCallback), mArg(aArg) { }
+  TNotification(Class* aInstance, Callback aCallback, Args* ... aArgs) :
+    mInstance(aInstance), mCallback(aCallback), mArgs(aArgs...) { }
   virtual ~TNotification() { mInstance = nullptr; }
 
   virtual void Process() override
-  {
-    (mInstance->*mCallback)(mArg);
-
-    mInstance = nullptr;
-    mCallback = nullptr;
-    mArg = nullptr;
-  }
+    { ProcessHelper(typename IndexSequenceFor<Args...>::Type()); }
 
 private:
   TNotification(const TNotification&);
   TNotification& operator = (const TNotification&);
 
+  template <size_t... Indices>
+    void ProcessHelper(IndexSequence<Indices...>)
+  {
+     (mInstance->*mCallback)(Get<Indices>(mArgs)...);
+  }
+
   Class* mInstance;
   Callback mCallback;
-  nsRefPtr<Arg> mArg;
+  Tuple<RefPtr<Args> ...> mArgs;
 };
 
 /**
  * Used to process notifications from core for the document accessible.
  */
 class NotificationController final : public EventQueue,
                                      public nsARefreshObserver
 {
@@ -115,28 +117,51 @@ public:
    */
   void ScheduleChildDocBinding(DocAccessible* aDocument);
 
   /**
    * Schedule the accessible tree update because of rendered text changes.
    */
   inline void ScheduleTextUpdate(nsIContent* aTextNode)
   {
-    if (mTextHash.PutEntry(aTextNode))
-      ScheduleProcessing();
+    // Make sure we are not called with a node that is not in the DOM tree or
+    // not visible.
+    MOZ_ASSERT(aTextNode->GetParentNode(), "A text node is not in DOM");
+    MOZ_ASSERT(aTextNode->GetPrimaryFrame(), "A text node doesn't have a frame");
+    MOZ_ASSERT(aTextNode->GetPrimaryFrame()->StyleVisibility()->IsVisible(),
+               "A text node is not visible");
+
+    mTextHash.PutEntry(aTextNode);
+    ScheduleProcessing();
   }
 
   /**
    * Pend accessible tree update for content insertion.
    */
   void ScheduleContentInsertion(Accessible* aContainer,
                                 nsIContent* aStartChildNode,
                                 nsIContent* aEndChildNode);
 
   /**
+   * Pend an accessible subtree relocation.
+   */
+  void ScheduleRelocation(Accessible* aOwner)
+  {
+    if (!mRelocations.Contains(aOwner) && mRelocations.AppendElement(aOwner)) {
+      ScheduleProcessing();
+    }
+  }
+
+  /**
+   * Start to observe refresh to make notifications and events processing after
+   * layout.
+   */
+  void ScheduleProcessing();
+
+  /**
    * Process the generic notification synchronously if there are no pending
    * layout changes and no notifications are pending or being processed right
    * now. Otherwise, queue it up to process asynchronously.
    *
    * @note  The caller must guarantee that the given instance still exists when
    *        the notification is processed.
    */
   template<class Class, class Arg>
@@ -148,57 +173,50 @@ public:
 #ifdef A11Y_LOG
       if (mozilla::a11y::logging::IsEnabled(mozilla::a11y::logging::eNotifications))
         mozilla::a11y::logging::Text("sync notification processing");
 #endif
       (aInstance->*aMethod)(aArg);
       return;
     }
 
-    nsRefPtr<Notification> notification =
+    RefPtr<Notification> notification =
       new TNotification<Class, Arg>(aInstance, aMethod, aArg);
     if (notification && mNotifications.AppendElement(notification))
       ScheduleProcessing();
   }
 
   /**
    * Schedule the generic notification to process asynchronously.
    *
    * @note  The caller must guarantee that the given instance still exists when
    *        the notification is processed.
    */
-  template<class Class, class Arg>
+  template<class Class>
   inline void ScheduleNotification(Class* aInstance,
-                                   typename TNotification<Class, Arg>::Callback aMethod,
-                                   Arg* aArg)
+                                   typename TNotification<Class>::Callback aMethod)
   {
-    nsRefPtr<Notification> notification =
-      new TNotification<Class, Arg>(aInstance, aMethod, aArg);
+    RefPtr<Notification> notification =
+      new TNotification<Class>(aInstance, aMethod);
     if (notification && mNotifications.AppendElement(notification))
       ScheduleProcessing();
   }
 
 #ifdef DEBUG
   bool IsUpdating() const
     { return mObservingState == eRefreshProcessingForUpdate; }
 #endif
 
 protected:
   virtual ~NotificationController();
 
   nsCycleCollectingAutoRefCnt mRefCnt;
   NS_DECL_OWNINGTHREAD
 
   /**
-   * Start to observe refresh to make notifications and events processing after
-   * layout.
-   */
-  void ScheduleProcessing();
-
-  /**
    * Return true if the accessible tree state update is pending.
    */
   bool IsUpdatePending();
 
 private:
   NotificationController(const NotificationController&);
   NotificationController& operator = (const NotificationController&);
 
@@ -221,57 +239,23 @@ private:
   /**
    * The presshell of the document accessible.
    */
   nsIPresShell* mPresShell;
 
   /**
    * Child documents that needs to be bound to the tree.
    */
-  nsTArray<nsRefPtr<DocAccessible> > mHangingChildDocuments;
+  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.
-    nsRefPtr<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<nsRefPtr<ContentInsertion> > mContentInsertions;
+  nsClassHashtable<nsRefPtrHashKey<Accessible>,
+                   nsTArray<nsCOMPtr<nsIContent>>> mContentInsertions;
 
   template<class T>
   class nsCOMPtrHashKey : public PLDHashEntryHdr
   {
   public:
     typedef T* KeyType;
     typedef const T* KeyTypePointer;
 
@@ -288,29 +272,28 @@ private:
 
     enum { ALLOW_MEMMOVE = true };
 
    protected:
      nsCOMPtr<T> mKey;
   };
 
   /**
-   * A pending accessible tree update notifications for rendered text changes.
+   * Pending accessible tree update notifications for rendered text changes.
    */
   nsTHashtable<nsCOMPtrHashKey<nsIContent> > mTextHash;
 
   /**
-   * Update the accessible tree for pending rendered text change notifications.
+   * Other notifications like DOM events. Don't make this an AutoTArray; we
+   * use SwapElements() on it.
    */
-  static PLDHashOperator TextEnumerator(nsCOMPtrHashKey<nsIContent>* aEntry,
-                                        void* aUserArg);
+  nsTArray<RefPtr<Notification> > mNotifications;
 
   /**
-   * Other notifications like DOM events. Don't make this an nsAutoTArray; we
-   * use SwapElements() on it.
+   * Holds all scheduled relocations.
    */
-  nsTArray<nsRefPtr<Notification> > mNotifications;
+  nsTArray<RefPtr<Accessible> > mRelocations;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_NotificationController_h_
--- a/accessible/base/Platform.h
+++ b/accessible/base/Platform.h
@@ -1,16 +1,18 @@
 /* -*- 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 <stdint.h>
 
+class nsString;
+
 namespace mozilla {
 namespace a11y {
 
 class ProxyAccessible;
 
 enum EPlatformDisabledState {
   ePlatformIsForceEnabled = -1,
   ePlatformIsEnabled = 0,
@@ -65,11 +67,14 @@ void ProxyDestroyed(ProxyAccessible*);
 
 /**
  * Callied when an event is fired on a proxied accessible.
  */
 void ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType);
 void ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t aState,
                            bool aEnabled);
 void ProxyCaretMoveEvent(ProxyAccessible* aTarget, int32_t aOffset);
+void ProxyTextChangeEvent(ProxyAccessible* aTarget, const nsString& aStr,
+                          int32_t aStart, uint32_t aLen, bool aIsInsert,
+                          bool aFromUser);
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/base/SelectionManager.cpp
+++ b/accessible/base/SelectionManager.cpp
@@ -24,17 +24,17 @@ using namespace mozilla;
 using namespace mozilla::a11y;
 using mozilla::dom::Selection;
 
 struct mozilla::a11y::SelData final
 {
   SelData(Selection* aSel, int32_t aReason) :
     mSel(aSel), mReason(aReason) {}
 
-  nsRefPtr<Selection> mSel;
+  RefPtr<Selection> mSel;
   int16_t mReason;
 
   NS_INLINE_DECL_REFCOUNTING(SelData)
 
 private:
   // Private destructor, to discourage deletion outside of Release():
   ~SelData() {}
 };
@@ -159,17 +159,17 @@ SelectionManager::ProcessTextSelChangeEv
   // event->mSel is correct.
   if (!selection)
     selection = event->mSel;
 
   mCaretOffset = caretCntr->DOMPointToOffset(selection->GetFocusNode(),
                                              selection->FocusOffset());
   mAccWithCaret = caretCntr;
   if (mCaretOffset != -1) {
-    nsRefPtr<AccCaretMoveEvent> caretMoveEvent =
+    RefPtr<AccCaretMoveEvent> caretMoveEvent =
       new AccCaretMoveEvent(caretCntr, mCaretOffset, aEvent->FromUserInput());
     nsEventShell::FireEvent(caretMoveEvent);
   }
 }
 
 NS_IMETHODIMP
 SelectionManager::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
                                          nsISelection* aSelection,
@@ -184,17 +184,17 @@ SelectionManager::NotifySelectionChanged
   if (logging::IsEnabled(logging::eSelection))
     logging::SelChange(aSelection, document, aReason);
 #endif
 
   if (document) {
     // Selection manager has longer lifetime than any document accessible,
     // so that we are guaranteed that the notification is processed before
     // the selection manager is destroyed.
-    nsRefPtr<SelData> selData =
+    RefPtr<SelData> selData =
       new SelData(static_cast<Selection*>(aSelection), aReason);
     document->HandleNotification<SelectionManager, SelData>
       (this, &SelectionManager::ProcessSelectionChanged, selData);
   }
 
   return NS_OK;
 }
 
@@ -221,17 +221,17 @@ SelectionManager::ProcessSelectionChange
 
   HyperTextAccessible* text = nsAccUtils::GetTextContainer(cntrNode);
   if (!text) {
     NS_NOTREACHED("We must reach document accessible implementing text interface!");
     return;
   }
 
   if (selection->GetType() == nsISelectionController::SELECTION_NORMAL) {
-    nsRefPtr<AccEvent> event =
+    RefPtr<AccEvent> event =
       new AccTextSelChangeEvent(text, selection, aSelData->mReason);
     text->Document()->FireDelayedEvent(event);
 
   } else if (selection->GetType() == nsISelectionController::SELECTION_SPELLCHECK) {
     // XXX: fire an event for container accessible of the focus/anchor range
     // of the spelcheck selection.
     text->Document()->FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED,
                                        text);
--- a/accessible/base/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
--- a/accessible/base/StyleInfo.h
+++ b/accessible/base/StyleInfo.h
@@ -34,15 +34,15 @@ public:
 private:
   StyleInfo() = delete;
   StyleInfo(const StyleInfo&) = delete;
   StyleInfo& operator = (const StyleInfo&) = delete;
 
   void Margin(Side aSide, nsAString& aValue);
 
   dom::Element* mElement;
-  nsRefPtr<nsStyleContext> mStyleContext;
+  RefPtr<nsStyleContext> mStyleContext;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/base/TextAttrs.cpp
+++ b/accessible/base/TextAttrs.cpp
@@ -455,17 +455,17 @@ TextAttrsMgr::FontFamilyTextAttr::
 {
   nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::font_family, aValue);
 }
 
 bool
 TextAttrsMgr::FontFamilyTextAttr::
   GetFontFamily(nsIFrame* aFrame, nsString& aFamily)
 {
-  nsRefPtr<nsFontMetrics> fm;
+  RefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
 
   gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
   gfxFont* font = fontGroup->GetFirstValidFont();
   gfxFontEntry* fontEntry = font->GetFontEntry();
   aFamily = fontEntry->FamilyName();
   return true;
 }
@@ -613,17 +613,17 @@ TextAttrsMgr::FontWeightTextAttr::
 }
 
 int32_t
 TextAttrsMgr::FontWeightTextAttr::
   GetFontWeight(nsIFrame* aFrame)
 {
   // nsFont::width isn't suitable here because it's necessary to expose real
   // value of font weight (used font might not have some font weight values).
-  nsRefPtr<nsFontMetrics> fm;
+  RefPtr<nsFontMetrics> fm;
   nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
 
   gfxFontGroup *fontGroup = fm->GetThebesFontGroup();
   gfxFont *font = fontGroup->GetFirstValidFont();
 
   // When there doesn't exist a bold font in the family and so the rendering of
   // a non-bold font face is changed so that the user sees what looks like a
   // bold font, i.e. synthetic bolding is used. IsSyntheticBold method is only
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,19 +244,27 @@ 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);
 
-  nsRefPtr<HyperTextAccessible> mRoot;
-  nsRefPtr<HyperTextAccessible> mStartContainer;
-  nsRefPtr<HyperTextAccessible> mEndContainer;
+  /**
+   * 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;
 };
 
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/base/TextUpdater.cpp
+++ b/accessible/base/TextUpdater.cpp
@@ -76,24 +76,24 @@ TextUpdater::DoUpdate(const nsAString& a
 
   // It could be single insertion or removal or the case of long strings. Do not
   // calculate the difference between long strings and prefer to fire pair of
   // insert/remove events as the old string was replaced on the new one.
   if (strLen1 == 0 || strLen2 == 0 ||
       strLen1 > kMaxStrLen || strLen2 > kMaxStrLen) {
     if (strLen1 > 0) {
       // Fire text change event for removal.
-      nsRefPtr<AccEvent> textRemoveEvent =
+      RefPtr<AccEvent> textRemoveEvent =
         new AccTextChangeEvent(mHyperText, mTextOffset, str1, false);
       mDocument->FireDelayedEvent(textRemoveEvent);
     }
 
     if (strLen2 > 0) {
       // Fire text change event for insertion.
-      nsRefPtr<AccEvent> textInsertEvent =
+      RefPtr<AccEvent> textInsertEvent =
         new AccTextChangeEvent(mHyperText, mTextOffset, str2, true);
       mDocument->FireDelayedEvent(textInsertEvent);
     }
 
     mDocument->MaybeNotifyOfValueChange(mHyperText);
 
     // Update the text.
     mTextLeaf->SetText(aNewText);
@@ -124,17 +124,17 @@ TextUpdater::DoUpdate(const nsAString& a
         row[colIdx] = std::min(upleft, std::min(left, up)) + 1;
       } else {
         row[colIdx] = prevRow[colIdx - 1];
       }
     }
   }
 
   // Compute events based on the difference.
-  nsTArray<nsRefPtr<AccEvent> > events;
+  nsTArray<RefPtr<AccEvent> > events;
   ComputeTextChangeEvents(str1, str2, entries, events);
 
   delete [] entries;
 
   // Fire events.
   for (int32_t idx = events.Length() - 1; idx >= 0; idx--)
     mDocument->FireDelayedEvent(events[idx]);
 
@@ -143,17 +143,17 @@ TextUpdater::DoUpdate(const nsAString& a
   // Update the text.
   mTextLeaf->SetText(aNewText);
 }
 
 void
 TextUpdater::ComputeTextChangeEvents(const nsAString& aStr1,
                                      const nsAString& aStr2,
                                      uint32_t* aEntries,
-                                     nsTArray<nsRefPtr<AccEvent> >& aEvents)
+                                     nsTArray<RefPtr<AccEvent> >& aEvents)
 {
   int32_t colIdx = aStr1.Length(), rowIdx = aStr2.Length();
 
   // Point at which strings last matched.
   int32_t colEnd = colIdx;
   int32_t rowEnd = rowIdx;
 
   int32_t colLen = colEnd + 1;
--- a/accessible/base/TextUpdater.h
+++ b/accessible/base/TextUpdater.h
@@ -46,37 +46,37 @@ private:
   TextUpdater& operator=(const TextUpdater&);
 
   /**
    * Fire text change events based on difference between strings.
    */
   void ComputeTextChangeEvents(const nsAString& aStr1,
                                const nsAString& aStr2,
                                uint32_t* aEntries,
-                               nsTArray<nsRefPtr<AccEvent> >& aEvents);
+                               nsTArray<RefPtr<AccEvent> >& aEvents);
 
   /**
    * Helper to create text change events for inserted text.
    */
   inline void FireInsertEvent(const nsAString& aText, uint32_t aAddlOffset,
-                              nsTArray<nsRefPtr<AccEvent> >& aEvents)
+                              nsTArray<RefPtr<AccEvent> >& aEvents)
   {
-    nsRefPtr<AccEvent> event =
+    RefPtr<AccEvent> event =
       new AccTextChangeEvent(mHyperText, mTextOffset + aAddlOffset,
                              aText, true);
     aEvents.AppendElement(event);
   }
 
   /**
    * Helper to create text change events for removed text.
    */
   inline void FireDeleteEvent(const nsAString& aText, uint32_t aAddlOffset,
-                              nsTArray<nsRefPtr<AccEvent> >& aEvents)
+                              nsTArray<RefPtr<AccEvent> >& aEvents)
   {
-    nsRefPtr<AccEvent> event =
+    RefPtr<AccEvent> event =
       new AccTextChangeEvent(mHyperText, mTextOffset + aAddlOffset,
                              aText, false);
     aEvents.AppendElement(event);
   }
 
   /**
    * The constant used to skip string difference calculation in case of long
    * strings.
--- a/accessible/base/TreeWalker.cpp
+++ b/accessible/base/TreeWalker.cpp
@@ -1,109 +1,143 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TreeWalker.h"
 
 #include "Accessible.h"
+#include "AccIterator.h"
 #include "nsAccessibilityService.h"
 #include "DocAccessible.h"
 
 #include "mozilla/dom/ChildIterator.h"
 #include "mozilla/dom/Element.h"
 
 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++);
+  }
 
   dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
   while (top) {
     while (nsIContent* childNode = top->GetNextChild()) {
-      bool isSubtreeHidden = false;
-      Accessible* accessible = mFlags & eWalkCache ?
-        mDoc->GetAccessible(childNode) :
-        GetAccService()->GetOrCreateAccessible(childNode, mContext,
-                                               &isSubtreeHidden);
+      bool skipSubtree = false;
+      Accessible* child = nullptr;
+      if (mFlags & eWalkCache) {
+        child = mDoc->GetAccessible(childNode);
+      }
+      else if (mContext->IsAcceptableChild(childNode)) {
+        child = GetAccService()->
+          GetOrCreateAccessible(childNode, mContext, &skipSubtree);
+      }
 
-      if (accessible)
-        return accessible;
+      // 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 (!isSubtreeHidden && 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 = mStateStack.AppendElement(dom::AllChildrenIterator(parent,
-                                                             mChildFilter));
-    while (nsIContent* childNode = top->GetNextChild()) {
-      if (childNode == mAnchorNode) {
-        mAnchorNode = parent;
-        return NextChild();
-      }
+    top = PushState(parent);
+    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();
 }
 
 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,61 +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&);
 
   /**
    * 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.
    */
   dom::AllChildrenIterator* PushState(nsIContent* aContent)
   {
-    return mStateStack.AppendElement(dom::AllChildrenIterator(aContent,
-                                                              mChildFilter));
+    return mStateStack.AppendElement(
+      dom::AllChildrenIterator(aContent, mChildFilter));
   }
 
   /**
    * Pop state from stack.
    */
   dom::AllChildrenIterator* PopState();
 
   DocAccessible* mDoc;
   Accessible* mContext;
   nsIContent* mAnchorNode;
-  nsAutoTArray<dom::AllChildrenIterator, 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/moz.build
+++ b/accessible/base/moz.build
@@ -92,10 +92,8 @@ else:
     ]
 
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['MOZ_ENABLE_GTK']:
     CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
 
 include('/ipc/chromium/chromium-config.mozbuild')
-
-FAIL_ON_WARNINGS = True
--- a/accessible/base/nsAccCache.h
+++ b/accessible/base/nsAccCache.h
@@ -7,45 +7,39 @@
 #define _nsAccCache_H_
 
 #include "xpcAccessibleDocument.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible cache utils
 ////////////////////////////////////////////////////////////////////////////////
 
-/**
- * Shutdown and removes the accessible from cache.
- */
 template <class T>
-static PLDHashOperator
-ClearCacheEntry(const void* aKey, nsRefPtr<T>& aAccessible, void* aUserArg)
+void
+UnbindCacheEntriesFromDocument(
+  nsRefPtrHashtable<nsPtrHashKey<const void>, T>& aCache)
 {
-  NS_ASSERTION(aAccessible, "Calling ClearCacheEntry with a nullptr pointer!");
-  if (aAccessible && !aAccessible->IsDefunct())
-    aAccessible->Shutdown();
-
-  return PL_DHASH_REMOVE;
-}
-
-template <class T>
-static PLDHashOperator
-UnbindCacheEntryFromDocument(const void* aKey, nsRefPtr<T>& aAccessible,
-                             void* aUserArg)
-{
-  MOZ_ASSERT(aAccessible && !aAccessible->IsDefunct());
-  aAccessible->Document()->UnbindFromDocument(aAccessible);
-
-  return PL_DHASH_REMOVE;
+  for (auto iter = aCache.Iter(); !iter.Done(); iter.Next()) {
+    T* accessible = iter.Data();
+    MOZ_ASSERT(accessible && !accessible->IsDefunct());
+    accessible->Document()->UnbindFromDocument(accessible);
+    iter.Remove();
+  }
 }
 
 /**
  * Clear the cache and shutdown the accessibles.
  */
-
 template <class T>
 static void
 ClearCache(nsRefPtrHashtable<nsPtrHashKey<const void>, T>& aCache)
 {
-  aCache.Enumerate(ClearCacheEntry<T>, nullptr);
+  for (auto iter = aCache.Iter(); !iter.Done(); iter.Next()) {
+    T* accessible = iter.Data();
+    MOZ_ASSERT(accessible);
+    if (accessible && !accessible->IsDefunct()) {
+      accessible->Shutdown();
+    }
+    iter.Remove();
+  }
 }
 
 #endif
--- a/accessible/base/nsAccUtils.cpp
+++ b/accessible/base/nsAccUtils.cpp
@@ -126,35 +126,37 @@ nsAccUtils::GetLevelForXULContainerItem(
     parentContainer.swap(container);
   }
 
   return level;
 }
 
 void
 nsAccUtils::SetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
-                                       nsIContent *aStartContent,
-                                       nsIContent *aTopContent)
+                                       nsIContent* aStartContent,
+                                       dom::Element* aTopEl)
 {
   nsAutoString live, relevant, busy;
-  nsIContent *ancestor = aStartContent;
+  nsIContent* ancestor = aStartContent;
   while (ancestor) {
 
     // container-relevant attribute
     if (relevant.IsEmpty() &&
         HasDefinedARIAToken(ancestor, nsGkAtoms::aria_relevant) &&
         ancestor->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_relevant, relevant))
       SetAccAttr(aAttributes, nsGkAtoms::containerRelevant, relevant);
 
     // container-live, and container-live-role attributes
     if (live.IsEmpty()) {
-      nsRoleMapEntry* role = aria::GetRoleMap(ancestor);
+      nsRoleMapEntry* role = nullptr;
+      if (ancestor->IsElement()) {
+        role = aria::GetRoleMap(ancestor->AsElement());
+      }
       if (HasDefinedARIAToken(ancestor, nsGkAtoms::aria_live)) {
-        ancestor->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_live,
-                          live);
+        ancestor->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_live, live);
       } else if (role) {
         GetLiveAttrValue(role->liveAttRule, live);
       }
       if (!live.IsEmpty()) {
         SetAccAttr(aAttributes, nsGkAtoms::containerLive, live);
         if (role) {
           SetAccAttr(aAttributes, nsGkAtoms::containerLiveRole,
                      role->ARIARoleString());
@@ -170,22 +172,22 @@ nsAccUtils::SetLiveContainerAttributes(n
     }
 
     // container-busy attribute
     if (busy.IsEmpty() &&
         HasDefinedARIAToken(ancestor, nsGkAtoms::aria_busy) &&
         ancestor->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_busy, busy))
       SetAccAttr(aAttributes, nsGkAtoms::containerBusy, busy);
 
-    if (ancestor == aTopContent)
+    if (ancestor == aTopEl)
       break;
 
     ancestor = ancestor->GetParent();
     if (!ancestor)
-      ancestor = aTopContent; // Use <body>/<frameset>
+      ancestor = aTopEl; // Use <body>/<frameset>
   }
 }
 
 bool
 nsAccUtils::HasDefinedARIAToken(nsIContent *aContent, nsIAtom *aAtom)
 {
   NS_ASSERTION(aContent, "aContent is null in call to HasDefinedARIAToken!");
 
--- a/accessible/base/nsAccUtils.h
+++ b/accessible/base/nsAccUtils.h
@@ -80,18 +80,18 @@ public:
   /**
    * Set container-foo live region attributes for the given node.
    *
    * @param aAttributes    where to store the attributes
    * @param aStartContent  node to start from
    * @param aTopContent    node to end at
    */
   static void SetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
-                                         nsIContent *aStartContent,
-                                         nsIContent *aTopContent);
+                                         nsIContent* aStartContent,
+                                         mozilla::dom::Element* aTopEl);
 
   /**
    * Any ARIA property of type boolean or NMTOKEN is undefined if the ARIA
    * property is not present, or is "" or "undefined". Do not call 
    * this method for properties of type string, decimal, IDREF or IDREFS.
    * 
    * Return true if the ARIA property is defined, otherwise false
    */
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -17,16 +17,17 @@
 #include "HTMLLinkAccessible.h"
 #include "HTMLListAccessible.h"
 #include "HTMLSelectAccessible.h"
 #include "HTMLTableAccessibleWrap.h"
 #include "HyperTextAccessibleWrap.h"
 #include "RootAccessible.h"
 #include "nsAccessiblePivot.h"
 #include "nsAccUtils.h"
+#include "nsArrayUtils.h"
 #include "nsAttrName.h"
 #include "nsEventShell.h"
 #include "nsIURI.h"
 #include "OuterDocAccessible.h"
 #include "Platform.h"
 #include "Role.h"
 #ifdef MOZ_ACCESSIBILITY_ATK
 #include "RootAccessibleWrap.h"
@@ -136,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());
 }
 
@@ -269,23 +270,82 @@ nsAccessibilityService::nsAccessibilityS
 
 nsAccessibilityService::~nsAccessibilityService()
 {
   NS_ASSERTION(gIsShutdown, "Accessibility wasn't shutdown!");
   gAccessibilityService = nullptr;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// nsIListenerChangeListener
+
+NS_IMETHODIMP
+nsAccessibilityService::ListenersChanged(nsIArray* aEventChanges)
+{
+  uint32_t targetCount;
+  nsresult rv = aEventChanges->GetLength(&targetCount);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  for (uint32_t i = 0 ; i < targetCount ; i++) {
+    nsCOMPtr<nsIEventListenerChange> change = do_QueryElementAt(aEventChanges, i);
+
+    nsCOMPtr<nsIDOMEventTarget> target;
+    change->GetTarget(getter_AddRefs(target));
+    nsCOMPtr<nsIContent> node(do_QueryInterface(target));
+    if (!node || !node->IsHTMLElement()) {
+      continue;
+    }
+    nsCOMPtr<nsIArray> listenerNames;
+    change->GetChangedListenerNames(getter_AddRefs(listenerNames));
+
+    uint32_t changeCount;
+    rv = listenerNames->GetLength(&changeCount);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    for (uint32_t i = 0 ; i < changeCount ; i++) {
+      nsCOMPtr<nsIAtom> listenerName = do_QueryElementAt(listenerNames, i);
+
+      // We are only interested in event listener changes which may
+      // make an element accessible or inaccessible.
+      if (listenerName != nsGkAtoms::onclick &&
+          listenerName != nsGkAtoms::onmousedown &&
+          listenerName != nsGkAtoms::onmouseup) {
+        continue;
+      }
+
+      nsIDocument* ownerDoc = node->OwnerDoc();
+      DocAccessible* document = GetExistingDocAccessible(ownerDoc);
+
+      // Always recreate for onclick changes.
+      if (document) {
+        if (nsCoreUtils::HasClickListener(node)) {
+          if (!document->GetAccessible(node)) {
+            document->RecreateAccessible(node);
+          }
+        } else {
+          if (document->GetAccessible(node)) {
+            document->RecreateAccessible(node);
+          }
+        }
+        break;
+      }
+    }
+  }
+  return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // nsISupports
 
 NS_IMPL_ISUPPORTS_INHERITED(nsAccessibilityService,
                             DocManager,
                             nsIAccessibilityService,
                             nsIAccessibleRetrieval,
                             nsIObserver,
+                            nsIListenerChangeListener,
                             nsISelectionListener) // from SelectionManager
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIObserver
 
 NS_IMETHODIMP
 nsAccessibilityService::Observe(nsISupports *aSubject, const char *aTopic,
                          const char16_t *aData)
@@ -391,57 +451,57 @@ nsAccessibilityService::CreatePluginAcce
                                                Accessible* aContext)
 {
   // nsPluginFrame means a plugin, so we need to use the accessibility support
   // of the plugin.
   if (aFrame->GetRect().IsEmpty())
     return nullptr;
 
 #if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK)
-  nsRefPtr<nsNPAPIPluginInstance> pluginInstance;
+  RefPtr<nsNPAPIPluginInstance> pluginInstance;
   if (NS_SUCCEEDED(aFrame->GetPluginInstance(getter_AddRefs(pluginInstance))) &&
       pluginInstance) {
 #ifdef XP_WIN
     if (!sPendingPlugins->Contains(aContent) &&
         (Preferences::GetBool("accessibility.delay_plugins") ||
          Compatibility::IsJAWS() || Compatibility::IsWE())) {
       nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
-      nsRefPtr<PluginTimerCallBack> cb = new PluginTimerCallBack(aContent);
+      RefPtr<PluginTimerCallBack> cb = new PluginTimerCallBack(aContent);
       timer->InitWithCallback(cb, Preferences::GetUint("accessibility.delay_plugin_time"),
                               nsITimer::TYPE_ONE_SHOT);
       sPluginTimers->AppendElement(timer);
       sPendingPlugins->AppendElement(aContent);
       return nullptr;
     }
 
     // We need to remove aContent from the pending plugins here to avoid
     // reentrancy.  When the timer fires it calls
     // DocAccessible::ContentInserted() which does the work async.
     sPendingPlugins->RemoveElement(aContent);
 
     // Note: pluginPort will be null if windowless.
     HWND pluginPort = nullptr;
     aFrame->GetPluginPort(&pluginPort);
 
-    nsRefPtr<Accessible> accessible =
+    RefPtr<Accessible> accessible =
       new HTMLWin32ObjectOwnerAccessible(aContent, aContext->Document(),
                                          pluginPort);
     return accessible.forget();
 
 #elif MOZ_ACCESSIBILITY_ATK
     if (!AtkSocketAccessible::gCanEmbed)
       return nullptr;
 
     // Note this calls into the plugin, so crazy things may happen and aFrame
     // may go away.
     nsCString plugId;
     nsresult rv = pluginInstance->GetValueFromPlugin(
       NPPVpluginNativeAccessibleAtkPlugId, &plugId);
     if (NS_SUCCEEDED(rv) && !plugId.IsEmpty()) {
-      nsRefPtr<AtkSocketAccessible> socketAccessible =
+      RefPtr<AtkSocketAccessible> socketAccessible =
         new AtkSocketAccessible(aContent, aContext->Document(), plugId);
 
       return socketAccessible.forget();
     }
 #endif
   }
 #endif
 
@@ -531,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
@@ -722,17 +782,17 @@ nsAccessibilityService::GetStringRole(ui
 
 #undef ROLE
 }
 
 NS_IMETHODIMP
 nsAccessibilityService::GetStringStates(uint32_t aState, uint32_t aExtraState,
                                         nsISupports **aStringStates)
 {
-  nsRefPtr<DOMStringList> stringStates = new DOMStringList();
+  RefPtr<DOMStringList> stringStates = new DOMStringList();
 
   uint64_t state = nsAccUtils::To64State(aState, aExtraState);
 
   // states
   if (state & states::UNAVAILABLE)
     stringStates->Add(NS_LITERAL_STRING("unavailable"));
   if (state & states::SELECTED)
     stringStates->Add(NS_LITERAL_STRING("selected"));
@@ -1022,38 +1082,36 @@ nsAccessibilityService::GetOrCreateAcces
 
 #ifdef DEBUG
   nsImageFrame* imageFrame = do_QueryFrame(frame);
   NS_ASSERTION(!imageFrame || !content->IsHTMLElement(nsGkAtoms::area),
                "Image map manages the area accessible creation!");
 #endif
 
   // Attempt to create an accessible based on what we know.
-  nsRefPtr<Accessible> newAcc;
+  RefPtr<Accessible> newAcc;
 
   // Create accessible for visible text frames.
   if (content->IsNodeOfType(nsINode::eTEXT)) {
-    nsAutoString text;
-    frame->GetRenderedText(&text, nullptr, nullptr, 0, UINT32_MAX);
+    nsIFrame::RenderedText text = frame->GetRenderedText(0,
+        UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
+        nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
     // Ignore not rendered text nodes and whitespace text nodes between table
     // cells.
-    if (text.IsEmpty() ||
-        (aContext->IsTableRow() && nsCoreUtils::IsWhitespaceString(text))) {
+    if (text.mString.IsEmpty() ||
+        (aContext->IsTableRow() && nsCoreUtils::IsWhitespaceString(text.mString))) {
       if (aIsSubtreeHidden)
         *aIsSubtreeHidden = true;
 
       return nullptr;
     }
 
     newAcc = CreateAccessibleByFrameType(frame, content, aContext);
-    if (!aContext->IsAcceptableChild(newAcc))
-      return nullptr;
-
     document->BindToDocument(newAcc, nullptr);
-    newAcc->AsTextLeaf()->SetText(text);
+    newAcc->AsTextLeaf()->SetText(text.mString);
     return newAcc;
   }
 
   if (content->IsHTMLElement(nsGkAtoms::map)) {
     // Create hyper text accessible for HTML map if it is used to group links
     // (see http://www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass). If the HTML
     // map rect is empty then it is used for links grouping. Otherwise it should
     // be used in conjunction with HTML image element and in this case we don't
@@ -1065,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))
@@ -1225,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()
@@ -1253,24 +1307,32 @@ nsAccessibilityService::Init()
   if (!observerService)
     return false;
 
   observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
 
   static const char16_t kInitIndicator[] = { '1', 0 };
   observerService->NotifyObservers(nullptr, "a11y-init-or-shutdown", kInitIndicator);
 
+  // Subscribe to EventListenerService.
+  nsCOMPtr<nsIEventListenerService> eventListenerService =
+    do_GetService("@mozilla.org/eventlistenerservice;1");
+  if (!eventListenerService)
+    return false;
+
+  eventListenerService->AddListenerChangeListener(this);
+
   for (uint32_t i = 0; i < ArrayLength(sMarkupMapList); i++)
     mMarkupMaps.Put(*sMarkupMapList[i].tag, &sMarkupMapList[i]);
 
 #ifdef A11Y_LOG
   logging::CheckEnv();
 #endif
 
-  if (XRE_GetProcessType() == GeckoProcessType_Default)
+  if (XRE_IsParentProcess())
     gApplicationAccessible = new ApplicationAccessibleWrap();
   else
     gApplicationAccessible = new ApplicationAccessible();
 
   NS_ADDREF(gApplicationAccessible); // will release in Shutdown()
 
 #ifdef MOZ_CRASHREPORTER
   CrashReporter::
@@ -1281,17 +1343,17 @@ nsAccessibilityService::Init()
 #ifdef XP_WIN
   sPendingPlugins = new nsTArray<nsCOMPtr<nsIContent> >;
   sPluginTimers = new nsTArray<nsCOMPtr<nsITimer> >;
 #endif
 
   gIsShutdown = false;
 
   // Now its safe to start platform accessibility.
-  if (XRE_GetProcessType() == GeckoProcessType_Default)
+  if (XRE_IsParentProcess())
     PlatformInit();
 
   return true;
 }
 
 void
 nsAccessibilityService::Shutdown()
 {
@@ -1324,48 +1386,42 @@ nsAccessibilityService::Shutdown()
   // accessibility service as shutdown to prevent calls of its methods.
   // Don't null accessibility service static member at this point to be safe
   // if someone will try to operate with it.
 
   NS_ASSERTION(!gIsShutdown, "Accessibility was shutdown already");
 
   gIsShutdown = true;
 
-  if (XRE_GetProcessType() == GeckoProcessType_Default)
+  if (XRE_IsParentProcess())
     PlatformShutdown();
 
   gApplicationAccessible->Shutdown();
   NS_RELEASE(gApplicationAccessible);
   gApplicationAccessible = nullptr;
 
   NS_IF_RELEASE(gXPCApplicationAccessible);
   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")) {
-    nsRefPtr<Accessible> accessible = new OuterDocAccessible(aContent, aDoc);
+    RefPtr<Accessible> accessible = new OuterDocAccessible(aContent, aDoc);
     return accessible.forget();
   }
 
-  nsRefPtr<Accessible> accessible;
+  RefPtr<Accessible> accessible;
 #ifdef MOZ_XUL
   // XUL controls
   if (role.EqualsLiteral("xul:alert")) {
     accessible = new XULAlertAccessible(aContent, aDoc);
 
   } else if (role.EqualsLiteral("xul:button")) {
     accessible = new XULButtonAccessible(aContent, aDoc);
 
@@ -1527,17 +1583,17 @@ nsAccessibilityService::CreateAccessible
 
 already_AddRefed<Accessible>
 nsAccessibilityService::CreateAccessibleByFrameType(nsIFrame* aFrame,
                                                     nsIContent* aContent,
                                                     Accessible* aContext)
 {
   DocAccessible* document = aContext->Document();
 
-  nsRefPtr<Accessible> newAcc;
+  RefPtr<Accessible> newAcc;
   switch (aFrame->AccessibleType()) {
     case eNoType:
       return nullptr;
     case eHTMLBRType:
       newAcc = new HTMLBRAccessible(aContent, document);
       break;
     case eHTMLButtonType:
       newAcc = new HTMLButtonAccessible(aContent, document);
@@ -1589,17 +1645,20 @@ nsAccessibilityService::CreateAccessible
       break;
     case eHTMLRangeType:
       newAcc = new HTMLRangeAccessible(aContent, document);
       break;
     case eHTMLSpinnerType:
       newAcc = new HTMLSpinnerAccessible(aContent, document);
       break;
     case eHTMLTableType:
-      newAcc = new HTMLTableAccessibleWrap(aContent, document);
+      if (aContent->IsHTMLElement(nsGkAtoms::table))
+        newAcc = new HTMLTableAccessibleWrap(aContent, document);
+      else
+        newAcc = new HyperTextAccessibleWrap(aContent, document);
       break;
     case eHTMLTableCellType:
       // Accessible HTML table cell should be a child of accessible HTML table
       // or its row (CSS HTML tables are polite to the used markup at
       // certain degree).
       // Otherwise create a generic text accessible to avoid text jamming
       // when reading by AT.
       if (aContext->IsHTMLTableRow() || aContext->IsHTMLTable())
@@ -1754,17 +1813,17 @@ NS_GetAccessibilityService(nsIAccessibil
   NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
   *aResult = nullptr;
 
   if (nsAccessibilityService::gAccessibilityService) {
     NS_ADDREF(*aResult = nsAccessibilityService::gAccessibilityService);
     return NS_OK;
   }
 
-  nsRefPtr<nsAccessibilityService> service = new nsAccessibilityService();
+  RefPtr<nsAccessibilityService> service = new nsAccessibilityService();
   NS_ENSURE_TRUE(service, NS_ERROR_OUT_OF_MEMORY);
 
   if (!service->Init()) {
     service->Shutdown();
     return NS_ERROR_FAILURE;
   }
 
   statistics::A11yInitialized();
@@ -1787,29 +1846,29 @@ nsAccessibilityService::CreateAccessible
                                                       nsGkAtoms::treechildren);
   if (!child)
     return nullptr;
 
   nsTreeBodyFrame* treeFrame = do_QueryFrame(child->GetPrimaryFrame());
   if (!treeFrame)
     return nullptr;
 
-  nsRefPtr<nsTreeColumns> treeCols = treeFrame->Columns();
+  RefPtr<nsTreeColumns> treeCols = treeFrame->Columns();
   int32_t count = 0;
   treeCols->GetCount(&count);
 
   // Outline of list accessible.
   if (count == 1) {
-    nsRefPtr<Accessible> accessible =
+    RefPtr<Accessible> accessible =
       new XULTreeAccessible(aContent, aDoc, treeFrame);
     return accessible.forget();
   }
 
   // Table or tree table accessible.
-  nsRefPtr<Accessible> accessible =
+  RefPtr<Accessible> accessible =
     new XULTreeGridAccessibleWrap(aContent, aDoc, treeFrame);
   return accessible.forget();
 }
 #endif
 
 ////////////////////////////////////////////////////////////////////////////////
 // Services
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/base/nsAccessibilityService.h
+++ b/accessible/base/nsAccessibilityService.h
@@ -10,18 +10,20 @@
 
 #include "mozilla/a11y/DocManager.h"
 #include "mozilla/a11y/FocusManager.h"
 #include "mozilla/a11y/Role.h"
 #include "mozilla/a11y/SelectionManager.h"
 #include "mozilla/Preferences.h"
 
 #include "nsIObserver.h"
+#include "nsIEventListenerService.h"
 
 class nsImageFrame;
+class nsIArray;
 class nsIPersistentProperties;
 class nsPluginFrame;
 class nsITreeView;
 
 namespace mozilla {
 namespace a11y {
 
 class ApplicationAccessible;
@@ -62,22 +64,26 @@ struct MarkupMapInfo {
 
 } // namespace a11y
 } // namespace mozilla
 
 class nsAccessibilityService final : public mozilla::a11y::DocManager,
                                      public mozilla::a11y::FocusManager,
                                      public mozilla::a11y::SelectionManager,
                                      public nsIAccessibilityService,
+                                     public nsIListenerChangeListener,
                                      public nsIObserver
 {
 public:
   typedef mozilla::a11y::Accessible Accessible;
   typedef mozilla::a11y::DocAccessible DocAccessible;
 
+  // nsIListenerChangeListener
+  NS_IMETHOD ListenersChanged(nsIArray* aEventChanges) override;
+
 protected:
   virtual ~nsAccessibilityService();
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIACCESSIBLERETRIEVAL
   NS_DECL_NSIOBSERVER
 
@@ -274,21 +280,20 @@ GetAccService()
 }
 
 /**
  * Return true if we're in a content process and not B2G.
  */
 inline bool
 IPCAccessibilityActive()
 {
-return false;
 #ifdef MOZ_B2G
   return false;
 #else
-  return XRE_GetProcessType() == GeckoProcessType_Content &&
+  return XRE_IsContentProcess() &&
     mozilla::Preferences::GetBool("accessibility.ipc_architecture.enabled", true);
 #endif
 }
 
 /**
  * Map nsIAccessibleEvents constants to strings. Used by
  * nsIAccessibleRetrieval::getStringEventType() method.
  */
@@ -374,13 +379,14 @@ static const char kEventTypeNames[][40] 
   "hyperlink number of anchors changed",     // EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED
   "hyperlink selected link changed",         // EVENT_HYPERLINK_SELECTED_LINK_CHANGED
   "hypertext link activated",                // EVENT_HYPERTEXT_LINK_ACTIVATED
   "hypertext link selected",                 // EVENT_HYPERTEXT_LINK_SELECTED
   "hyperlink start index changed",           // EVENT_HYPERLINK_START_INDEX_CHANGED
   "hypertext changed",                       // EVENT_HYPERTEXT_CHANGED
   "hypertext links count changed",           // EVENT_HYPERTEXT_NLINKS_CHANGED
   "object attribute changed",                // EVENT_OBJECT_ATTRIBUTE_CHANGED
-  "virtual cursor changed"                   // EVENT_VIRTUALCURSOR_CHANGED
+  "virtual cursor changed",                   // EVENT_VIRTUALCURSOR_CHANGED
+  "text value change",                       // EVENT_TEXT_VALUE_CHANGE
 };
 
 #endif /* __nsIAccessibilityService_h__ */
 
--- a/accessible/base/nsAccessiblePivot.cpp
+++ b/accessible/base/nsAccessiblePivot.cpp
@@ -84,17 +84,17 @@ nsAccessiblePivot::GetPosition(nsIAccess
   NS_IF_ADDREF(*aPosition = ToXPC(mPosition));
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccessiblePivot::SetPosition(nsIAccessible* aPosition)
 {
-  nsRefPtr<Accessible> position = nullptr;
+  RefPtr<Accessible> position = nullptr;
 
   if (aPosition) {
     position = aPosition->ToInternalAccessible();
     if (!position || !IsDescendantOf(position, GetActiveRoot()))
       return NS_ERROR_INVALID_ARG;
   }
 
   // Swap old position with new position, saves us an AddRef/Release.
@@ -163,17 +163,17 @@ nsAccessiblePivot::SetTextRange(nsIAcces
   // smaller than 0, both should be -1.
   NS_ENSURE_TRUE(aStartOffset <= aEndOffset &&
                  (aStartOffset >= 0 || (aStartOffset != -1 && aEndOffset != -1)),
                  NS_ERROR_INVALID_ARG);
 
   nsCOMPtr<nsIAccessible> xpcAcc = do_QueryInterface(aTextAccessible);
   NS_ENSURE_ARG(xpcAcc);
 
-  nsRefPtr<Accessible> acc = xpcAcc->ToInternalAccessible();
+  RefPtr<Accessible> acc = xpcAcc->ToInternalAccessible();
   NS_ENSURE_ARG(acc);
 
   HyperTextAccessible* position = acc->AsHyperText();
   if (!position || !IsDescendantOf(position, GetActiveRoot()))
     return NS_ERROR_INVALID_ARG;
 
   // Make sure the given offsets don't exceed the character count.
   if (aEndOffset > static_cast<int32_t>(position->CharacterCount()))
@@ -638,17 +638,17 @@ nsAccessiblePivot::IsDescendantOf(Access
   return false;
 }
 
 bool
 nsAccessiblePivot::MovePivotInternal(Accessible* aPosition,
                                      PivotMoveReason aReason,
                                      bool aIsFromUserInput)
 {
-  nsRefPtr<Accessible> oldPosition = mPosition.forget();
+  RefPtr<Accessible> oldPosition = mPosition.forget();
   mPosition = aPosition;
   int32_t oldStart = mStartOffset, oldEnd = mEndOffset;
   mStartOffset = mEndOffset = -1;
 
   return NotifyOfPivotChange(oldPosition, oldStart, oldEnd, aReason,
                              aIsFromUserInput);
 }
 
--- a/accessible/base/nsAccessiblePivot.h
+++ b/accessible/base/nsAccessiblePivot.h
@@ -109,27 +109,27 @@ private:
    *
    */
   Accessible* AdjustStartPosition(Accessible* aAccessible, RuleCache& aCache,
                                   uint16_t* aFilterResult, nsresult* aResult);
 
   /*
    * The root accessible.
    */
-  nsRefPtr<Accessible> mRoot;
+  RefPtr<Accessible> mRoot;
 
   /*
    * The temporary modal root accessible.
    */
-  nsRefPtr<Accessible> mModalRoot;
+  RefPtr<Accessible> mModalRoot;
 
   /*
    * The current pivot position.
    */
-  nsRefPtr<Accessible> mPosition;
+  RefPtr<Accessible> mPosition;
 
   /*
    * The text start offset ofthe pivot.
    */
   int32_t mStartOffset;
 
   /*
    * The text end offset ofthe pivot.
--- 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) ||
@@ -97,65 +110,65 @@ nsCoreUtils::DispatchClickEvent(nsITreeB
   // Dispatch mouse events.
   nsWeakFrame tcFrame = tcContent->GetPrimaryFrame();
   nsIFrame* rootFrame = presShell->GetRootFrame();
 
   nsPoint offset;
   nsIWidget *rootWidget =
     rootFrame->GetViewExternal()->GetNearestWidget(&offset);
 
-  nsRefPtr<nsPresContext> presContext = presShell->GetPresContext();
+  RefPtr<nsPresContext> presContext = presShell->GetPresContext();
 
   int32_t cnvdX = presContext->CSSPixelsToDevPixels(tcX + x + 1) +
     presContext->AppUnitsToDevPixels(offset.x);
   int32_t cnvdY = presContext->CSSPixelsToDevPixels(tcY + y + 1) +
     presContext->AppUnitsToDevPixels(offset.y);
 
   // XUL is just desktop, so there is no real reason for senfing touch events.
-  DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, cnvdX, cnvdY,
+  DispatchMouseEvent(eMouseDown, cnvdX, cnvdY,
                      tcContent, tcFrame, presShell, rootWidget);
 
-  DispatchMouseEvent(NS_MOUSE_BUTTON_UP, cnvdX, cnvdY,
+  DispatchMouseEvent(eMouseUp, cnvdX, cnvdY,
                      tcContent, tcFrame, presShell, rootWidget);
 }
 
 void
-nsCoreUtils::DispatchMouseEvent(uint32_t aEventType, int32_t aX, int32_t aY,
+nsCoreUtils::DispatchMouseEvent(EventMessage aMessage, int32_t aX, int32_t aY,
                                 nsIContent *aContent, nsIFrame *aFrame,
                                 nsIPresShell *aPresShell, nsIWidget *aRootWidget)
 {
-  WidgetMouseEvent event(true, aEventType, aRootWidget,
+  WidgetMouseEvent event(true, aMessage, aRootWidget,
                          WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
 
   event.refPoint = LayoutDeviceIntPoint(aX, aY);
 
   event.clickCount = 1;
   event.button = WidgetMouseEvent::eLeftButton;
   event.time = PR_IntervalNow();
   event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
 
   nsEventStatus status = nsEventStatus_eIgnore;
   aPresShell->HandleEventWithTarget(&event, aFrame, aContent, &status);
 }
 
 void
-nsCoreUtils::DispatchTouchEvent(uint32_t aEventType, int32_t aX, int32_t aY,
+nsCoreUtils::DispatchTouchEvent(EventMessage aMessage, int32_t aX, int32_t aY,
                                 nsIContent* aContent, nsIFrame* aFrame,
                                 nsIPresShell* aPresShell, nsIWidget* aRootWidget)
 {
   if (!dom::TouchEvent::PrefEnabled())
     return;
 
-  WidgetTouchEvent event(true, aEventType, aRootWidget);
+  WidgetTouchEvent event(true, aMessage, aRootWidget);
 
   event.time = PR_IntervalNow();
 
   // XXX: Touch has an identifier of -1 to hint that it is synthesized.
-  nsRefPtr<dom::Touch> t = new dom::Touch(-1, LayoutDeviceIntPoint(aX, aY),
-                                          nsIntPoint(1, 1), 0.0f, 1.0f);
+  RefPtr<dom::Touch> t = new dom::Touch(-1, LayoutDeviceIntPoint(aX, aY),
+                                        LayoutDeviceIntPoint(1, 1), 0.0f, 1.0f);
   t->SetTarget(aContent);
   event.touches.AppendElement(t);
   nsEventStatus status = nsEventStatus_eIgnore;
   aPresShell->HandleEventWithTarget(&event, aFrame, aContent, &status);
 }
 
 uint32_t
 nsCoreUtils::GetAccessKeyFor(nsIContent* aContent)
@@ -205,38 +218,16 @@ nsCoreUtils::GetDOMNodeFromDOMPoint(nsIN
     // from the given DOM point is used as result node.
     if (aOffset != childCount)
       return aNode->GetChildAt(aOffset);
   }
 
   return aNode;
 }
 
-nsIContent*
-nsCoreUtils::GetRoleContent(nsINode *aNode)
-{
-  nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
-  if (!content) {
-    nsCOMPtr<nsIDocument> doc(do_QueryInterface(aNode));
-    if (doc) {
-      nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(aNode));
-      if (htmlDoc) {
-        nsCOMPtr<nsIDOMHTMLElement> bodyElement;
-        htmlDoc->GetBody(getter_AddRefs(bodyElement));
-        content = do_QueryInterface(bodyElement);
-      }
-      else {
-        return doc->GetDocumentElement();
-      }
-    }
-  }
-
-  return content;
-}
-
 bool
 nsCoreUtils::IsAncestorOf(nsINode *aPossibleAncestorNode,
                           nsINode *aPossibleDescendantNode,
                           nsINode *aRootNode)
 {
   NS_ENSURE_TRUE(aPossibleAncestorNode && aPossibleDescendantNode, false);
 
   nsINode *parentNode = aPossibleDescendantNode;
@@ -420,17 +411,17 @@ bool
 nsCoreUtils::IsTabDocument(nsIDocument* aDocumentNode)
 {
   nsCOMPtr<nsIDocShellTreeItem> treeItem(aDocumentNode->GetDocShell());
 
   nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
   treeItem->GetParent(getter_AddRefs(parentTreeItem));
 
   // Tab document running in own process doesn't have parent.
-  if (XRE_GetProcessType() == GeckoProcessType_Content)
+  if (XRE_IsContentProcess())
     return !parentTreeItem;
 
   // Parent of docshell for tab document running in chrome process is root.
   nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
   treeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
 
   return parentTreeItem == rootTreeItem;
 }
@@ -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
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef 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;
@@ -23,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.
    *
@@ -44,40 +51,42 @@ public:
    */
   static void DispatchClickEvent(nsITreeBoxObject *aTreeBoxObj,
                                  int32_t aRowIndex, nsITreeColumn *aColumn,
                                  const nsAString& aPseudoElt = EmptyString());
 
   /**
    * Send mouse event to the given element.
    *
-   * @param aEventType   [in] an event type (see BasicEvents.h for constants)
+   * @param aMessage     [in] an event message (see EventForwards.h)
    * @param aX           [in] x coordinate in dev pixels
    * @param aY           [in] y coordinate in dev pixels
    * @param aContent     [in] the element
    * @param aFrame       [in] frame of the element
    * @param aPresShell   [in] the presshell for the element
    * @param aRootWidget  [in] the root widget of the element
    */
-  static void DispatchMouseEvent(uint32_t aEventType, int32_t aX, int32_t aY,
+  static void DispatchMouseEvent(mozilla::EventMessage aMessage,
+                                 int32_t aX, int32_t aY,
                                  nsIContent *aContent, nsIFrame *aFrame,
                                  nsIPresShell *aPresShell, nsIWidget *aRootWidget);
 
   /**
    * Send a touch event with a single touch point to the given element.
    *
-   * @param aEventType   [in] an event type (see BasicEvents.h for constants)
+   * @param aMessage     [in] an event message (see EventForwards.h)
    * @param aX           [in] x coordinate in dev pixels
    * @param aY           [in] y coordinate in dev pixels
    * @param aContent     [in] the element
    * @param aFrame       [in] frame of the element
    * @param aPresShell   [in] the presshell for the element
    * @param aRootWidget  [in] the root widget of the element
    */
-  static void DispatchTouchEvent(uint32_t aEventType, int32_t aX, int32_t aY,
+  static void DispatchTouchEvent(mozilla::EventMessage aMessage,
+                                 int32_t aX, int32_t aY,
                                  nsIContent* aContent, nsIFrame* aFrame,
                                  nsIPresShell* aPresShell, nsIWidget* aRootWidget);
 
   /**
    * Return an accesskey registered on the given element by
    * EventStateManager or 0 if there is no registered accesskey.
    *
    * @param aContent - the given element.
@@ -95,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
@@ -306,11 +304,26 @@ public:
   /**
    * Returns true if the given character is whitespace symbol.
    */
   static bool IsWhitespace(char16_t aChar)
   {
     return aChar == ' ' || aChar == '\n' ||
       aChar == '\r' || aChar == '\t' || aChar == 0xa0;
   }
+
+  /*
+   * Return true if there are any observers of accessible events.
+   */
+  static bool AccEventObserversExist();
+
+  /**
+   * Notify accessible event observers of an event.
+   */
+  static void DispatchAccEvent(RefPtr<nsIAccessibleEvent> aEvent);
+
+  /**
+   * Return a role attribute on XBL bindings of the element.
+   */
+  static void XBLBindingRole(const nsIContent* aEl, nsAString& aRole);
 };
 
 #endif
--- a/accessible/base/nsEventShell.cpp
+++ b/accessible/base/nsEventShell.cpp
@@ -37,17 +37,17 @@ nsEventShell::FireEvent(AccEvent* aEvent
 }
 
 void
 nsEventShell::FireEvent(uint32_t aEventType, Accessible* aAccessible,
                         EIsFromUserInput aIsFromUserInput)
 {
   NS_ENSURE_TRUE_VOID(aAccessible);
 
-  nsRefPtr<AccEvent> event = new AccEvent(aEventType, aAccessible,
+  RefPtr<AccEvent> event = new AccEvent(aEventType, aAccessible,
                                           aIsFromUserInput);
 
   FireEvent(event);
 }
 
 void 
 nsEventShell::GetEventAttributes(nsINode *aNode,
                                  nsIPersistentProperties *aAttributes)
--- a/accessible/base/nsEventShell.h
+++ b/accessible/base/nsEventShell.h
@@ -36,17 +36,17 @@ public:
                         mozilla::a11y::EIsFromUserInput aIsFromUserInput = mozilla::a11y::eAutoDetect);
 
   /**
    * Fire state change event.
    */
   static void FireEvent(mozilla::a11y::Accessible* aTarget, uint64_t aState,
                         bool aIsEnabled, bool aIsFromUserInput)
   {
-    nsRefPtr<mozilla::a11y::AccStateChangeEvent> stateChangeEvent =
+    RefPtr<mozilla::a11y::AccStateChangeEvent> stateChangeEvent =
       new mozilla::a11y::AccStateChangeEvent(aTarget, aState, aIsEnabled,
                                              (aIsFromUserInput ?
                                                mozilla::a11y::eFromUserInput :
                                                mozilla::a11y::eNoUserInput));
     FireEvent(stateChangeEvent);
   }
 
   /**
--- a/accessible/base/nsTextEquivUtils.cpp
+++ b/accessible/base/nsTextEquivUtils.cpp
@@ -134,18 +134,20 @@ nsTextEquivUtils::AppendTextEquivFromTex
           }
         }
       }
     }
     
     if (aContent->TextLength() > 0) {
       nsIFrame *frame = aContent->GetPrimaryFrame();
       if (frame) {
-        nsresult rv = frame->GetRenderedText(aString);
-        NS_ENSURE_SUCCESS(rv, rv);
+        nsIFrame::RenderedText text = frame->GetRenderedText(0,
+            UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
+            nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
+        aString->Append(text.mString);
       } else {
         // If aContent is an object that is display: none, we have no a frame.
         aContent->AppendTextTo(*aString);
       }
       if (isHTMLBlock && !aString->IsEmpty()) {
         aString->Append(char16_t(' '));
       }
     }
--- a/accessible/generic/ARIAGridAccessible.cpp
+++ b/accessible/generic/ARIAGridAccessible.cpp
@@ -542,18 +542,19 @@ ARIARowAccessible::
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(ARIARowAccessible, Accessible)
 
 GroupPos
 ARIARowAccessible::GroupPosition()
 {
   int32_t count = 0, index = 0;
-  if (nsCoreUtils::GetUIntAttr(nsAccUtils::TableFor(this)->GetContent(),
-                               nsGkAtoms::aria_rowcount, &count) &&
+  Accessible* table = nsAccUtils::TableFor(this);
+  if (table && nsCoreUtils::GetUIntAttr(table->GetContent(),
+                                        nsGkAtoms::aria_rowcount, &count) &&
       nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_rowindex, &index)) {
     return GroupPos(0, index, count);
   }
 
   return AccessibleWrap::GroupPosition();
 }
 
 
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -10,16 +10,17 @@
 #include "AccCollector.h"
 #include "AccGroupInfo.h"
 #include "AccIterator.h"
 #include "nsAccUtils.h"
 #include "nsAccessibilityService.h"
 #include "ApplicationAccessible.h"
 #include "nsEventShell.h"
 #include "nsTextEquivUtils.h"
+#include "DocAccessibleChild.h"
 #include "Relation.h"
 #include "Role.h"
 #include "RootAccessible.h"
 #include "States.h"
 #include "StyleInfo.h"
 #include "TableAccessible.h"
 #include "TableCellAccessible.h"
 #include "TreeWalker.h"
@@ -60,32 +61,32 @@
 #include "nsIAtom.h"
 #include "nsIURI.h"
 #include "nsArrayUtils.h"
 #include "nsIMutableArray.h"
 #include "nsIObserverService.h"
 #include "nsIServiceManager.h"
 #include "nsWhitespaceTokenizer.h"
 #include "nsAttrName.h"
-#include "nsNetUtil.h"
 
 #ifdef DEBUG
 #include "nsIDOMCharacterData.h"
 #endif
 
 #include "mozilla/Assertions.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/unused.h"
 #include "mozilla/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
@@ -102,19 +103,20 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Accessible)
 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(Accessible, LastRelease())
 
 Accessible::Accessible(nsIContent* aContent, DocAccessible* aDoc) :
   mContent(aContent), mDoc(aDoc),
   mParent(nullptr), mIndexInParent(-1), mChildrenFlags(eChildrenUninitialized),
   mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0),
-  mIndexOfEmbeddedChild(-1), mRoleMapEntry(nullptr)
+  mRoleMapEntry(nullptr)
 {
   mBits.groupInfo = nullptr;
+  mInt.mIndexOfEmbeddedChild = -1;
 }
 
 Accessible::~Accessible()
 {
   NS_ASSERTION(!mDoc, "LastRelease was never called!?!");
 }
 
 ENameValueFlag
@@ -296,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;
 
@@ -388,20 +384,22 @@ Accessible::VisibilityState()
   // Zero area rects can occur in the first frame of a multi-frame text flow,
   // in which case the rendered text is not empty and the frame should not be
   // marked invisible.
   // XXX Can we just remove this check? Why do we need to mark empty
   // text invisible?
   if (frame->GetType() == nsGkAtoms::textFrame &&
       !(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
       frame->GetRect().IsEmpty()) {
-    nsAutoString renderedText;
-    frame->GetRenderedText(&renderedText, nullptr, nullptr, 0, 1);
-    if (renderedText.IsEmpty())
+    nsIFrame::RenderedText text = frame->GetRenderedText(0,
+        UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
+        nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
+    if (text.mString.IsEmpty()) {
       return states::INVISIBLE;
+    }
   }
 
   return 0;
 }
 
 uint64_t
 Accessible::NativeState()
 {
@@ -529,20 +527,20 @@ Accessible::ChildAtPoint(int32_t aX, int
   NS_ENSURE_TRUE(rootFrame, nullptr);
 
   nsIFrame* startFrame = rootFrame;
 
   // Check whether the point is at popup content.
   nsIWidget* rootWidget = rootFrame->GetView()->GetNearestWidget(nullptr);
   NS_ENSURE_TRUE(rootWidget, nullptr);
 
-  nsIntRect rootRect;
+  LayoutDeviceIntRect rootRect;
   rootWidget->GetScreenBounds(rootRect);
 
-  WidgetMouseEvent dummyEvent(true, NS_MOUSE_MOVE, rootWidget,
+  WidgetMouseEvent dummyEvent(true, eMouseMove, rootWidget,
                               WidgetMouseEvent::eSynthesized);
   dummyEvent.refPoint = LayoutDeviceIntPoint(aX - rootRect.x, aY - rootRect.y);
 
   nsIFrame* popupFrame = nsLayoutUtils::
     GetPopupFrameForEventCoordinates(accDocument->PresContext()->GetRootPresContext(),
                                      &dummyEvent);
   if (popupFrame) {
     // If 'this' accessible is not inside the popup then ignore the popup when
@@ -813,45 +811,90 @@ 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
 Accessible::HandleAccEvent(AccEvent* aEvent)
 {
   NS_ENSURE_ARG_POINTER(aEvent);
 
-  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 (IPCAccessibilityActive() && Document()) {
+    DocAccessibleChild* ipcDoc = mDoc->IPCDoc();
+    MOZ_ASSERT(ipcDoc);
+    if (ipcDoc) {
+      uint64_t id = aEvent->GetAccessible()->IsDoc() ? 0 :
+        reinterpret_cast<uintptr_t>(aEvent->GetAccessible());
+
+      switch(aEvent->GetEventType()) {
+        case nsIAccessibleEvent::EVENT_SHOW:
+          ipcDoc->ShowEvent(downcast_accEvent(aEvent));
+          break;
+
+        case nsIAccessibleEvent::EVENT_HIDE:
+          ipcDoc->SendHideEvent(id);
+          break;
+
+        case nsIAccessibleEvent::EVENT_REORDER:
+          // reorder events on the application acc aren't necessary to tell the parent
+          // about new top level documents.
+          if (!aEvent->GetAccessible()->IsApplication())
+            ipcDoc->SendEvent(id, aEvent->GetEventType());
+          break;
+        case nsIAccessibleEvent::EVENT_STATE_CHANGE: {
+                                                       AccStateChangeEvent* event = downcast_accEvent(aEvent);
+                                                       ipcDoc->SendStateChangeEvent(id, event->GetState(),
+                                                                                    event->IsStateEnabled());
+                                                       break;
+                                                     }
+        case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: {
+          AccCaretMoveEvent* event = downcast_accEvent(aEvent);
+          ipcDoc->SendCaretMoveEvent(id, event->GetCaretOffset());
+          break;
+        }
+        case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
+        case nsIAccessibleEvent::EVENT_TEXT_REMOVED: {
+          AccTextChangeEvent* event = downcast_accEvent(aEvent);
+          ipcDoc->SendTextChangeEvent(id, event->ModifiedText(),
+                                      event->GetStartOffset(),
+                                      event->GetLength(),
+                                      event->IsTextInserted(),
+                                      event->IsFromUserInput());
+          break;
+                                                     }
+        default:
+                                                         ipcDoc->SendEvent(id, aEvent->GetEventType());
+      }
+    }
+  }
+
+  if (nsCoreUtils::AccEventObserversExist()) {
+    nsCoreUtils::DispatchAccEvent(MakeXPCEvent(aEvent));
   }
 
   return NS_OK;
 }
 
 already_AddRefed<nsIPersistentProperties>
 Accessible::Attributes()
 {
@@ -954,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));
@@ -1183,35 +1226,37 @@ Accessible::ApplyARIAState(uint64_t* aSt
 
     // We only force the readonly bit off if we have a real mapping for the aria
     // role. This preserves the ability for screen readers to use readonly
     // (primarily on the document) as the hint for creating a virtual buffer.
     if (mRoleMapEntry->role != roles::NOTHING)
       *aState &= ~states::READONLY;
 
     if (mContent->HasID()) {
-      // If has a role & ID and aria-activedescendant on the container, assume focusable
-      nsIContent *ancestorContent = mContent;
-      while ((ancestorContent = ancestorContent->GetParent()) != nullptr) {
-        if (ancestorContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant)) {
-            // ancestor has activedescendant property, this content could be active
+      // If has a role & ID and aria-activedescendant on the container, assume
+      // focusable.
+      const Accessible* ancestor = this;
+      while ((ancestor = ancestor->Parent()) && !ancestor->IsDoc()) {
+        dom::Element* el = ancestor->Elm();
+        if (el &&
+            el->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant)) {
           *aState |= states::FOCUSABLE;
           break;
         }
       }
     }
   }
 
   if (*aState & states::FOCUSABLE) {
-    // Special case: aria-disabled propagates from ancestors down to any focusable descendant
-    nsIContent *ancestorContent = mContent;
-    while ((ancestorContent = ancestorContent->GetParent()) != nullptr) {
-      if (ancestorContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled,
-                                       nsGkAtoms::_true, eCaseMatters)) {
-          // ancestor has aria-disabled property, this is disabled
+    // Propogate aria-disabled from ancestors down to any focusable descendant.
+    const Accessible* ancestor = this;
+    while ((ancestor = ancestor->Parent()) && !ancestor->IsDoc()) {
+      dom::Element* el = ancestor->Elm();
+      if (el && el->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled,
+                                nsGkAtoms::_true, eCaseMatters)) {
         *aState |= states::UNAVAILABLE;
         break;
       }
     }
   }
 
   // special case: A native button element whose role got transformed by ARIA to a toggle button
   // Also applies to togglable button menus, like in the Dev Tools Web Console.
@@ -1270,31 +1315,24 @@ Accessible::Value(nsString& aValue)
     nsTextEquivUtils::GetTextEquivFromSubtree(this, aValue);
     return;
   }
 
   // Value of combobox is a text of current or selected item.
   if (mRoleMapEntry->Is(nsGkAtoms::combobox)) {
     Accessible* option = CurrentItem();
     if (!option) {
-      Accessible* listbox = nullptr;
-      ARIAOwnsIterator iter(this);
-      while ((listbox = iter.Next()) && !listbox->IsListControl());
-
-      if (!listbox) {
-        uint32_t childCount = ChildCount();
-        for (uint32_t idx = 0; idx < childCount; idx++) {
-          Accessible* child = mChildren.ElementAt(idx);
-          if (child->IsListControl())
-            listbox = child;
+      uint32_t childCount = ChildCount();
+      for (uint32_t idx = 0; idx < childCount; idx++) {
+        Accessible* child = mChildren.ElementAt(idx);
+        if (child->IsListControl()) {
+          option = child->GetSelectedItem(0);
+          break;
         }
       }
-
-      if (listbox)
-        option = listbox->GetSelectedItem(0);
     }
 
     if (option)
       nsTextEquivUtils::GetTextEquivFromSubtree(option, aValue);
   }
 }
 
 double
@@ -1555,18 +1593,17 @@ Accessible::RelationByType(RelationType 
       if (mContent->IsXULElement(nsGkAtoms::description))
         rel.AppendIter(new IDRefsIterator(mDoc, mContent,
                                           nsGkAtoms::control));
 
       return rel;
     }
 
     case RelationType::NODE_CHILD_OF: {
-      Relation rel(new ARIAOwnedByIterator(this));
-
+      Relation rel;
       // This is an ARIA tree or treegrid that doesn't use owns, so we need to
       // get the parent the hard way.
       if (mRoleMapEntry && (mRoleMapEntry->role == roles::OUTLINEITEM ||
                             mRoleMapEntry->role == roles::LISTITEM ||
                             mRoleMapEntry->role == roles::ROW)) {
         rel.AppendTarget(GetGroupInfo()->ConceptualParent());
       }
 
@@ -1585,31 +1622,29 @@ Accessible::RelationByType(RelationType 
             rel.AppendTarget(Parent());
         }
       }
 
       return rel;
     }
 
     case RelationType::NODE_PARENT_OF: {
-      Relation rel(new ARIAOwnsIterator(this));
-
       // ARIA tree or treegrid can do the hierarchy by @aria-level, ARIA trees
       // also can be organized by groups.
       if (mRoleMapEntry &&
           (mRoleMapEntry->role == roles::OUTLINEITEM ||
            mRoleMapEntry->role == roles::LISTITEM ||
            mRoleMapEntry->role == roles::ROW ||
            mRoleMapEntry->role == roles::OUTLINE ||
            mRoleMapEntry->role == roles::LIST ||
            mRoleMapEntry->role == roles::TREE_TABLE)) {
-        rel.AppendIter(new ItemIterator(this));
+        return Relation(new ItemIterator(this));
       }
 
-      return rel;
+      return Relation();
     }
 
     case RelationType::CONTROLLED_BY:
       return Relation(new RelatedAccIterator(Document(), mContent,
                                              nsGkAtoms::aria_controls));
 
     case RelationType::CONTROLLER_FOR: {
       Relation rel(new IDRefsIterator(mDoc, mContent,
@@ -1739,17 +1774,17 @@ Accessible::DoCommand(nsIContent *aConte
 
     void Revoke()
     {
       mAcc = nullptr;
       mContent = nullptr;
     }
 
   private:
-    nsRefPtr<Accessible> mAcc;
+    RefPtr<Accessible> mAcc;
     nsCOMPtr<nsIContent> mContent;
     uint32_t mIdx;
   };
 
   nsIContent* content = aContent ? aContent : mContent.get();
   nsCOMPtr<nsIRunnable> runnable = new Runnable(this, content, aActionIndex);
   NS_DispatchToMainThread(runnable);
 }
@@ -1775,25 +1810,29 @@ Accessible::DispatchClickEvent(nsIConten
   // Compute x and y coordinates.
   nsPoint point;
   nsCOMPtr<nsIWidget> widget = frame->GetNearestWidget(point);
   if (!widget)
     return;
 
   nsSize size = frame->GetSize();
 
-  nsRefPtr<nsPresContext> presContext = presShell->GetPresContext();
+  RefPtr<nsPresContext> presContext = presShell->GetPresContext();
   int32_t x = presContext->AppUnitsToDevPixels(point.x + size.width / 2);
   int32_t y = presContext->AppUnitsToDevPixels(point.y + size.height / 2);
 
   // Simulate a touch interaction by dispatching touch events with mouse events.
-  nsCoreUtils::DispatchTouchEvent(NS_TOUCH_START, x, y, aContent, frame, presShell, widget);
-  nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, x, y, aContent, frame, presShell, widget);
-  nsCoreUtils::DispatchTouchEvent(NS_TOUCH_END, x, y, aContent, frame, presShell, widget);
-  nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_UP, x, y, aContent, frame, presShell, widget);
+  nsCoreUtils::DispatchTouchEvent(eTouchStart, x, y, aContent, frame,
+                                  presShell, widget);
+  nsCoreUtils::DispatchMouseEvent(eMouseDown, x, y, aContent, frame,
+                                  presShell, widget);
+  nsCoreUtils::DispatchTouchEvent(eTouchEnd, x, y, aContent, frame,
+                                  presShell, widget);
+  nsCoreUtils::DispatchMouseEvent(eMouseUp, x, y, aContent, frame,
+                                  presShell, widget);
 }
 
 void
 Accessible::ScrollToPoint(uint32_t aCoordinateType, int32_t aX, int32_t aY)
 {
   nsIFrame* frame = GetFrame();
   if (!frame)
     return;
@@ -1916,18 +1955,18 @@ Accessible::NativeName(nsString& aName)
 void
 Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent)
 {
   NS_PRECONDITION(aParent, "This method isn't used to set null parent!");
 
   if (mParent) {
     if (mParent != aParent) {
       NS_ERROR("Adopting child!");
+      mParent->InvalidateChildrenGroupInfo();
       mParent->RemoveChild(this);
-      mParent->InvalidateChildrenGroupInfo();
     } else {
       NS_ERROR("Binding to the same parent!");
       return;
     }
   }
 
   mParent = aParent;
   mIndexInParent = aIndexInParent;
@@ -1939,34 +1978,38 @@ 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();
 #endif
   mParent = nullptr;
   mIndexInParent = -1;
-  mIndexOfEmbeddedChild = -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
 {
@@ -2081,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
@@ -2197,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);
@@ -2429,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
@@ -155,16 +155,18 @@ public:
    */
   virtual nsINode* GetNode() const;
   inline already_AddRefed<nsIDOMNode> DOMNode() const
   {
     nsCOMPtr<nsIDOMNode> DOMNode = do_QueryInterface(GetNode());
     return DOMNode.forget();
   }
   nsIContent* GetContent() const { return mContent; }
+  mozilla::dom::Element* Elm() const
+    { return mContent && mContent->IsElement() ? mContent->AsElement() : nullptr; }
 
   /**
    * Return node type information of DOM node associated with the accessible.
    */
   bool IsContent() const
     { return GetNode() && GetNode()->IsNodeOfType(nsINode::eCONTENT); }
 
   /**
@@ -389,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; }
 
@@ -483,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
@@ -527,21 +530,16 @@ public:
   virtual nsRect RelativeBounds(nsIFrame** aRelativeFrame) const;
 
   /**
    * Selects the accessible within its container if applicable.
    */
   virtual void SetSelected(bool aSelect);
 
   /**
-   * Extend selection to this accessible.
-   */
-  void ExtendSelection() { };
-
-  /**
    * Select the accessible within its container.
    */
   void TakeSelection();
 
   /**
    * Focus the accessible.
    */
   virtual void TakeFocus();
@@ -565,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); }
 
@@ -585,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; }
 
@@ -616,16 +617,26 @@ public:
   bool IsMenuPopup() const { return mType == eMenuPopupType; }
 
   bool IsProxy() const { return mType == eProxyType; }
   ProxyAccessible* Proxy() const
   {
     MOZ_ASSERT(IsProxy());
     return mBits.proxy;
   }
+  uint32_t ProxyInterfaces() const
+  {
+    MOZ_ASSERT(IsProxy());
+    return mInt.mProxyInterfaces;
+  }
+  void SetProxyInterfaces(uint32_t aInterfaces)
+  {
+    MOZ_ASSERT(IsProxy());
+    mInt.mProxyInterfaces = aInterfaces;
+  }
 
   bool IsOuterDoc() const { return mType == eOuterDocType; }
   OuterDocAccessible* AsOuterDoc();
 
   bool IsProgress() const { return mType == eProgressType; }
 
   bool IsRoot() const { return mType == eRootType; }
   a11y::RootAccessible* AsRoot();
@@ -746,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);
 
@@ -846,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); }
@@ -895,31 +912,54 @@ public:
   {
     if (aIsSurviving)
       mStateFlags |= eSurvivingInUpdate;
     else
       mStateFlags &= ~eSurvivingInUpdate;
   }
 
   /**
+   * Get/set repositioned bit indicating that the accessible was moved in
+   * the accessible tree, i.e. the accessible tree structure differs from DOM.
+   */
+  bool IsRelocated() const { return mStateFlags & eRelocated; }
+  void SetRelocated(bool aRelocated)
+  {
+    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);
 
@@ -940,18 +980,18 @@ protected:
   /**
    * Cache accessible children.
    */
   virtual void CacheChildren();
 
   /**
    * Set accessible parent and index in parent.
    */
-  virtual void BindToParent(Accessible* aParent, uint32_t aIndexInParent);
-  virtual void UnbindFromParent();
+  void BindToParent(Accessible* aParent, uint32_t aIndexInParent);
+  void UnbindFromParent();
 
   /**
    * Return sibling accessible at the given offset.
    */
   virtual Accessible* GetSiblingAtOffset(int32_t aOffset,
                                          nsresult *aError = nullptr) const;
 
   /**
@@ -985,28 +1025,31 @@ protected:
     eIsNotInDocument = 1 << 1, // accessible is not in document
     eSharedNode = 1 << 2, // accessible shares DOM node from another accessible
     eNotNodeMapEntry = 1 << 3, // accessible shouldn't be in document node map
     eHasNumericValue = 1 << 4, // accessible has a numeric value
     eGroupInfoDirty = 1 << 5, // accessible needs to update group info
     eSubtreeMutating = 1 << 6, // subtree is being mutated
     eIgnoreDOMUIEvent = 1 << 7, // don't process DOM UI events for a11y events
     eSurvivingInUpdate = 1 << 8, // parent drops children to recollect them
+    eRelocated = 1 << 9, // accessible was moved in tree
+    eNoXBLKids = 1 << 10, // accessible don't allows XBL children
 
-    eLastStateFlag = eSurvivingInUpdate
+    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
 
   /**
@@ -1096,25 +1139,25 @@ protected:
    * Flag all children group info as needing to be updated.
    */
   void InvalidateChildrenGroupInfo();
 
   // Data Members
   nsCOMPtr<nsIContent> mContent;
   DocAccessible* mDoc;
 
-  nsRefPtr<Accessible> mParent;
-  nsTArray<nsRefPtr<Accessible> > mChildren;
+  RefPtr<Accessible> mParent;
+  nsTArray<RefPtr<Accessible> > mChildren;
   int32_t mIndexInParent;
 
   static const uint8_t kChildrenFlagsBits = 2;
-  static const uint8_t kStateFlagsBits = 9;
-  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;
@@ -1123,17 +1166,21 @@ protected:
   void StaticAsserts() const;
   void AssertInMutatingSubtree() const;
 
   friend class DocAccessible;
   friend class xpcAccessible;
   friend class AutoTreeMutation;
 
   nsAutoPtr<mozilla::a11y::EmbeddedObjCollector> mEmbeddedObjCollector;
-  int32_t mIndexOfEmbeddedChild;
+  union {
+    int32_t mIndexOfEmbeddedChild;
+    uint32_t mProxyInterfaces;
+  } mInt;
+
   friend class EmbeddedObjCollector;
 
   union
   {
     AccGroupInfo* groupInfo;
     ProxyAccessible* proxy;
   } mBits;
   friend class AccGroupInfo;
--- a/accessible/generic/ApplicationAccessible.cpp
+++ b/accessible/generic/ApplicationAccessible.cpp
@@ -1,26 +1,25 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* vim:expandtab:shiftwidth=4:tabstop=4:
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ApplicationAccessible.h"
 
 #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,22 +187,20 @@ ApplicationAccessible::CacheChildren()
   if (NS_FAILED(rv))
     return;
 
   bool hasMore = false;
   windowEnumerator->HasMoreElements(&hasMore);
   while (hasMore) {
     nsCOMPtr<nsISupports> window;
     windowEnumerator->GetNext(getter_AddRefs(window));
-    nsCOMPtr<nsIDOMWindow> DOMWindow = do_QueryInterface(window);
+    nsCOMPtr<nsPIDOMWindowOuter> DOMWindow = do_QueryInterface(window);
     if (DOMWindow) {
-      nsCOMPtr<nsIDOMDocument> DOMDocument;
-      DOMWindow->GetDocument(getter_AddRefs(DOMDocument));
-      if (DOMDocument) {
-        nsCOMPtr<nsIDocument> docNode(do_QueryInterface(DOMDocument));
+      nsCOMPtr<nsIDocument> docNode = DOMWindow->GetDoc();
+      if (docNode) {
         GetAccService()->GetDocAccessible(docNode); // ensure creation
       }
     }
     windowEnumerator->HasMoreElements(&hasMore);
   }
 }
 
 Accessible*
--- a/accessible/generic/BaseAccessibles.cpp
+++ b/accessible/generic/BaseAccessibles.cpp
@@ -48,188 +48,201 @@ 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.
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // LinkableAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
-LinkableAccessible::
-  LinkableAccessible(nsIContent* aContent, DocAccessible* aDoc) :
-  AccessibleWrap(aContent, aDoc),
-  mActionAcc(nullptr),
-  mIsLink(false),
-  mIsOnclick(false)
-{
-}
-
 NS_IMPL_ISUPPORTS_INHERITED0(LinkableAccessible, AccessibleWrap)
 
 ////////////////////////////////////////////////////////////////////////////////
 // LinkableAccessible. nsIAccessible
 
 void
 LinkableAccessible::TakeFocus()
 {
-  if (mActionAcc)
-    mActionAcc->TakeFocus();
-  else
+  if (Accessible* actionAcc = ActionWalk()) {
+    actionAcc->TakeFocus();
+  } else {
     AccessibleWrap::TakeFocus();
+  }
 }
 
 uint64_t
 LinkableAccessible::NativeLinkState() const
 {
-  if (mIsLink)
-    return states::LINKED | (mActionAcc->LinkState() & states::TRAVERSED);
+  bool isLink;
+  Accessible* actionAcc =
+    const_cast<LinkableAccessible*>(this)->ActionWalk(&isLink);
+  if (isLink) {
+    return states::LINKED | (actionAcc->LinkState() & states::TRAVERSED);
+  }
 
   return 0;
 }
 
 void
 LinkableAccessible::Value(nsString& aValue)
 {
   aValue.Truncate();
 
   Accessible::Value(aValue);
-  if (!aValue.IsEmpty())
+  if (!aValue.IsEmpty()) {
     return;
+  }
 
-  if (aValue.IsEmpty() && mIsLink)
-    mActionAcc->Value(aValue);
+  bool isLink;
+  Accessible* actionAcc = ActionWalk(&isLink);
+  if (isLink) {
+    actionAcc->Value(aValue);
+  }
 }
 
-
 uint8_t
 LinkableAccessible::ActionCount()
 {
-  return (mIsOnclick || mIsLink) ? 1 : 0;
+  bool isLink, isOnclick, isLabelWithControl;
+  ActionWalk(&isLink, &isOnclick, &isLabelWithControl);
+  return (isLink || isOnclick || isLabelWithControl) ? 1 : 0;
+}
+
+Accessible*
+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;
+  }
+
+  // XXX: The logic looks broken since the click listener may be registered
+  // on non accessible node in parent chain but this node is skipped when tree
+  // is traversed.
+  Accessible* walkUpAcc = this;
+  while ((walkUpAcc = walkUpAcc->Parent()) && !walkUpAcc->IsDoc()) {
+    if (walkUpAcc->LinkState() & states::LINKED) {
+      if (aIsLink) {
+        *aIsLink = true;
+      }
+      return walkUpAcc;
+    }
+
+    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) {
-    if (mIsLink)
+    bool isOnclick, isLink, isLabelWithControl;
+    ActionWalk(&isLink, &isOnclick, &isLabelWithControl);
+    if (isLink) {
       aName.AssignLiteral("jump");
-    else if (mIsOnclick)
+    } else if (isOnclick || isLabelWithControl) {
       aName.AssignLiteral("click");
+    }
   }
 }
 
 bool
 LinkableAccessible::DoAction(uint8_t aIndex)
 {
-  if (aIndex != eAction_Jump)
+  if (aIndex != eAction_Jump) {
     return false;
+  }
 
-  return mActionAcc ? mActionAcc->DoAction(aIndex) :
-    AccessibleWrap::DoAction(aIndex);
+  if (Accessible* actionAcc = ActionWalk()) {
+    return actionAcc->DoAction(aIndex);
+  }
+
+  return AccessibleWrap::DoAction(aIndex);
 }
 
 KeyBinding
 LinkableAccessible::AccessKey() const
 {
-  return mActionAcc ?
-    mActionAcc->AccessKey() : Accessible::AccessKey();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// LinkableAccessible. Accessible
+  if (const Accessible* actionAcc =
+    const_cast<LinkableAccessible*>(this)->ActionWalk()) {
+    return actionAcc->AccessKey();
+  }
 
-void
-LinkableAccessible::Shutdown()
-{
-  mIsLink = false;
-  mIsOnclick = false;
-  mActionAcc = nullptr;
-  AccessibleWrap::Shutdown();
+  return Accessible::AccessKey();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // LinkableAccessible: HyperLinkAccessible
 
 already_AddRefed<nsIURI>
 LinkableAccessible::AnchorURIAt(uint32_t aAnchorIndex)
 {
-  if (mIsLink) {
-    NS_ASSERTION(mActionAcc->IsLink(), "HyperLink isn't implemented.");
+  bool isLink;
+  Accessible* actionAcc = ActionWalk(&isLink);
+  if (isLink) {
+    NS_ASSERTION(actionAcc->IsLink(), "HyperLink isn't implemented.");
 
-    if (mActionAcc->IsLink())
-      return mActionAcc->AnchorURIAt(aAnchorIndex);
+    if (actionAcc->IsLink()) {
+      return actionAcc->AnchorURIAt(aAnchorIndex);
+    }
   }
 
   return nullptr;
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// LinkableAccessible: Accessible protected
-
-void
-LinkableAccessible::BindToParent(Accessible* aParent,
-                                 uint32_t aIndexInParent)
-{
-  AccessibleWrap::BindToParent(aParent, aIndexInParent);
-
-  // Cache action content.
-  mActionAcc = nullptr;
-  mIsLink = false;
-  mIsOnclick = false;
-
-  if (nsCoreUtils::HasClickListener(mContent)) {
-    mIsOnclick = true;
-    return;
-  }
-
-  // XXX: The logic looks broken since the click listener may be registered
-  // on non accessible node in parent chain but this node is skipped when tree
-  // is traversed.
-  Accessible* walkUpAcc = this;
-  while ((walkUpAcc = walkUpAcc->Parent()) && !walkUpAcc->IsDoc()) {
-    if (walkUpAcc->LinkState() & states::LINKED) {
-      mIsLink = true;
-      mActionAcc = walkUpAcc;
-      return;
-    }
-
-    if (nsCoreUtils::HasClickListener(walkUpAcc->GetContent())) {
-      mActionAcc = walkUpAcc;
-      mIsOnclick = true;
-      return;
-    }
-  }
-}
-
-void
-LinkableAccessible::UnbindFromParent()
-{
-  mActionAcc = nullptr;
-  mIsLink = false;
-  mIsOnclick = false;
-
-  AccessibleWrap::UnbindFromParent();
-}
 
 ////////////////////////////////////////////////////////////////////////////////
 // DummyAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 uint64_t
 DummyAccessible::NativeState()
 {
--- 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;
 };
 
 /**
@@ -51,48 +53,44 @@ protected:
  * report the state of the host link (traveled or not) and can activate (click)
  * the host accessible programmatically.
  */
 class LinkableAccessible : public AccessibleWrap
 {
 public:
   enum { eAction_Jump = 0 };
 
-  LinkableAccessible(nsIContent* aContent, DocAccessible* aDoc);
+  LinkableAccessible(nsIContent* aContent, DocAccessible* aDoc) :
+    AccessibleWrap(aContent, aDoc)
+  {
+  }
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // Accessible
-  virtual void Shutdown() override;
   virtual void Value(nsString& aValue) override;
   virtual uint64_t NativeLinkState() const override;
   virtual void TakeFocus() override;
 
   // 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* aIsLabelWithControl = nullptr);
   // HyperLinkAccessible
   virtual already_AddRefed<nsIURI> AnchorURIAt(uint32_t aAnchorIndex) override;
 
 protected:
   virtual ~LinkableAccessible() {}
 
-  // Accessible
-  virtual void BindToParent(Accessible* aParent, uint32_t aIndexInParent) override;
-  virtual void UnbindFromParent() override;
-
-  /**
-   * Parent accessible that provides an action for this linkable accessible.
-   */
-  Accessible* mActionAcc;
-  bool mIsLink;
-  bool mIsOnclick;
 };
 
 /**
  * A simple accessible that gets its enumerated role.
  */
 template<a11y::role R>
 class EnumRoleAccessible : public AccessibleWrap
 {
--- 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 {
 
@@ -40,17 +41,17 @@ DocAccessible::FireDelayedEvent(AccEvent
 #endif
 
   mNotificationController->QueueEvent(aEvent);
 }
 
 inline void
 DocAccessible::FireDelayedEvent(uint32_t aEventType, Accessible* aTarget)
 {
-  nsRefPtr<AccEvent> event = new AccEvent(aEventType, aTarget);
+  RefPtr<AccEvent> event = new AccEvent(aEventType, aTarget);
   FireDelayedEvent(event);
 }
 
 inline void
 DocAccessible::BindChildDocument(DocAccessible* aDocument)
 {
   mNotificationController->ScheduleChildDocBinding(aDocument);
 }
@@ -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();
@@ -108,28 +122,28 @@ inline void
 DocAccessible::NotifyOfLoad(uint32_t aLoadEventType)
 {
   mLoadState |= eDOMLoaded;
   mLoadEventType = aLoadEventType;
 
   // If the document is loaded completely then network activity was presumingly
   // caused by file loading. Fire busy state change event.
   if (HasLoadState(eCompletelyLoaded) && IsLoadEventTarget()) {
-    nsRefPtr<AccEvent> stateEvent =
+    RefPtr<AccEvent> stateEvent =
       new AccStateChangeEvent(this, states::BUSY, false);
     FireDelayedEvent(stateEvent);
   }
 }
 
 inline void
 DocAccessible::MaybeNotifyOfValueChange(Accessible* aAccessible)
 {
   a11y::role role = aAccessible->Role();
   if (role == roles::ENTRY || role == roles::COMBOBOX)
-    FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible);
+    FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE, aAccessible);
 }
 
 inline Accessible*
 DocAccessible::GetAccessibleEvenIfNotInMapOrContainer(nsINode* aNode) const
 {
   Accessible* acc = GetAccessibleEvenIfNotInMap(aNode);
   return acc ? acc : GetContainerAccessible(aNode);
 }
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Accessible-inl.h"
 #include "AccIterator.h"
 #include "DocAccessible-inl.h"
 #include "DocAccessibleChild.h"
@@ -70,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)
@@ -108,29 +108,51 @@ DocAccessible::~DocAccessible()
 // nsISupports
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(DocAccessible)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DocAccessible, Accessible)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotificationController)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVirtualCursor)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildDocuments)
-  tmp->mDependentIDsHash.EnumerateRead(CycleCollectorTraverseDepIDsEntry, &cb);
+  for (auto iter = tmp->mDependentIDsHash.Iter(); !iter.Done(); iter.Next()) {
+    AttrRelProviderArray* providers = iter.UserData();
+
+    for (int32_t jdx = providers->Length() - 1; jdx >= 0; jdx--) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
+        cb, "content of dependent ids hash entry of document accessible");
+
+      AttrRelProvider* provider = (*providers)[jdx];
+      cb.NoteXPCOMChild(provider->mContent);
+
+      NS_ASSERTION(provider->mContent->IsInDoc(),
+                   "Referred content is not in document!");
+    }
+  }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAccessibleCache)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchorJumpElm)
+  for (auto it = tmp->mARIAOwnsHash.ConstIter(); !it.Done(); it.Next()) {
+    nsTArray<RefPtr<Accessible> >* ar = it.UserData();
+    for (uint32_t i = 0; i < ar->Length(); i++) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
+                                         "mARIAOwnsHash entry item");
+      cb.NoteXPCOMChild(ar->ElementAt(i));
+    }
+  }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DocAccessible, Accessible)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mNotificationController)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mVirtualCursor)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildDocuments)
   tmp->mDependentIDsHash.Clear();
   tmp->mNodeToAccessibleMap.Clear();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessibleCache)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnchorJumpElm)
+  tmp->mARIAOwnsHash.Clear();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DocAccessible)
   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsIAccessiblePivotObserver)
@@ -648,17 +670,17 @@ NS_IMETHODIMP
 DocAccessible::Observe(nsISupports* aSubject, const char* aTopic,
                        const char16_t* aData)
 {
   if (!nsCRT::strcmp(aTopic,"obs_documentCreated")) {    
     // State editable will now be set, readonly is now clear
     // Normally we only fire delayed events created from the node, not an
     // accessible object. See the AccStateChangeEvent constructor for details
     // about this exceptional case.
-    nsRefPtr<AccEvent> event =
+    RefPtr<AccEvent> event =
       new AccStateChangeEvent(this, states::EDITABLE, true);
     FireDelayedEvent(event);
   }
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -666,17 +688,17 @@ DocAccessible::Observe(nsISupports* aSub
 
 NS_IMETHODIMP
 DocAccessible::OnPivotChanged(nsIAccessiblePivot* aPivot,
                               nsIAccessible* aOldAccessible,
                               int32_t aOldStart, int32_t aOldEnd,
                               PivotMoveReason aReason,
                               bool aIsFromUserInput)
 {
-  nsRefPtr<AccEvent> event =
+  RefPtr<AccEvent> event =
     new AccVCChangeEvent(
       this, (aOldAccessible ? aOldAccessible->ToInternalAccessible() : nullptr),
       aOldStart, aOldEnd, aReason,
       aIsFromUserInput ? eFromUserInput : eNoUserInput);
   nsEventShell::FireEvent(event);
 
   return NS_OK;
 }
@@ -687,31 +709,36 @@ DocAccessible::OnPivotChanged(nsIAccessi
 NS_IMPL_NSIDOCUMENTOBSERVER_CORE_STUB(DocAccessible)
 NS_IMPL_NSIDOCUMENTOBSERVER_LOAD_STUB(DocAccessible)
 NS_IMPL_NSIDOCUMENTOBSERVER_STYLE_STUB(DocAccessible)
 
 void
 DocAccessible::AttributeWillChange(nsIDocument* aDocument,
                                    dom::Element* aElement,
                                    int32_t aNameSpaceID,
-                                   nsIAtom* aAttribute, int32_t aModType)
+                                   nsIAtom* aAttribute, int32_t aModType,
+                                   const nsAttrValue* aNewValue)
 {
   Accessible* accessible = GetAccessible(aElement);
   if (!accessible) {
     if (aElement != mContent)
       return;
 
     accessible = this;
   }
 
   // Update dependent IDs cache. Take care of elements that are accessible
   // because dependent IDs cache doesn't contain IDs from non accessible
   // elements.
   if (aModType != nsIDOMMutationEvent::ADDITION)
-    RemoveDependentIDsFor(aElement, aAttribute);
+    RemoveDependentIDsFor(accessible, aAttribute);
+
+  if (aAttribute == nsGkAtoms::id) {
+    RelocateARIAOwnedIfNeeded(aElement);
+  }
 
   // Store the ARIA attribute old value so that it can be used after
   // attribute change. Note, we assume there's no nested ARIA attribute
   // changes. If this happens then we should end up with keeping a stack of
   // old values.
 
   // XXX TODO: bugs 472142, 472143.
   // Here we will want to cache whatever attribute values we are interested
@@ -725,20 +752,28 @@ DocAccessible::AttributeWillChange(nsIDo
   }
 
   if (aAttribute == nsGkAtoms::aria_disabled ||
       aAttribute == nsGkAtoms::disabled)
     mStateBitWasOn = accessible->Unavailable();
 }
 
 void
+DocAccessible::NativeAnonymousChildListChange(nsIDocument* aDocument,
+                                              nsIContent* aContent,
+                                              bool aIsRemove)
+{
+}
+
+void
 DocAccessible::AttributeChanged(nsIDocument* aDocument,
                                 dom::Element* aElement,
                                 int32_t aNameSpaceID, nsIAtom* aAttribute,
-                                int32_t aModType)
+                                int32_t aModType,
+                                const nsAttrValue* aOldValue)
 {
   NS_ASSERTION(!IsDefunct(),
                "Attribute changed called on defunct document accessible!");
 
   // Proceed even if the element is not accessible because element may become
   // accessible if it gets certain attribute.
   if (UpdateAccessibleOnAttrChange(aElement, aAttribute))
     return;
@@ -762,17 +797,17 @@ DocAccessible::AttributeChanged(nsIDocum
 
   // Update dependent IDs cache. Take care of accessible elements because no
   // accessible element means either the element is not accessible at all or
   // its accessible will be created later. It doesn't make sense to keep
   // dependent IDs for non accessible elements. For the second case we'll update
   // dependent IDs cache when its accessible is created.
   if (aModType == nsIDOMMutationEvent::MODIFICATION ||
       aModType == nsIDOMMutationEvent::ADDITION) {
-    AddDependentIDsFor(aElement, aAttribute);
+    AddDependentIDsFor(accessible, aAttribute);
   }
 }
 
 // DocAccessible protected member
 void
 DocAccessible::AttributeChangedImpl(Accessible* aAccessible,
                                     int32_t aNameSpaceID, nsIAtom* aAttribute)
 {
@@ -801,21 +836,21 @@ DocAccessible::AttributeChangedImpl(Acce
   // ARIA's aria-disabled does not affect the disabled state bit.
   if (aAttribute == nsGkAtoms::disabled ||
       aAttribute == nsGkAtoms::aria_disabled) {
     // Do nothing if state wasn't changed (like @aria-disabled was removed but
     // @disabled is still presented).
     if (aAccessible->Unavailable() == mStateBitWasOn)
       return;
 
-    nsRefPtr<AccEvent> enabledChangeEvent =
+    RefPtr<AccEvent> enabledChangeEvent =
       new AccStateChangeEvent(aAccessible, states::ENABLED, mStateBitWasOn);
     FireDelayedEvent(enabledChangeEvent);
 
-    nsRefPtr<AccEvent> sensitiveChangeEvent =
+    RefPtr<AccEvent> sensitiveChangeEvent =
       new AccStateChangeEvent(aAccessible, states::SENSITIVE, mStateBitWasOn);
     FireDelayedEvent(sensitiveChangeEvent);
     return;
   }
 
   // Check for namespaced ARIA attribute
   if (aNameSpaceID == kNameSpaceID_None) {
     // Check for hyphenated aria-foo property?
@@ -864,43 +899,47 @@ DocAccessible::AttributeChangedImpl(Acce
       FireDelayedEvent(nsIAccessibleEvent::EVENT_DESCRIPTION_CHANGE, aAccessible);
 
     return;
   }
 
   if (aAttribute == nsGkAtoms::aria_busy) {
     bool isOn = elm->AttrValueIs(aNameSpaceID, aAttribute, nsGkAtoms::_true,
                                  eCaseMatters);
-    nsRefPtr<AccEvent> event =
+    RefPtr<AccEvent> event =
       new AccStateChangeEvent(aAccessible, states::BUSY, isOn);
     FireDelayedEvent(event);
     return;
   }
 
+  if (aAttribute == nsGkAtoms::id) {
+    RelocateARIAOwnedIfNeeded(elm);
+  }
+
   // ARIA or XUL selection
   if ((aAccessible->GetContent()->IsXULElement() &&
        aAttribute == nsGkAtoms::selected) ||
       aAttribute == nsGkAtoms::aria_selected) {
     Accessible* widget =
       nsAccUtils::GetSelectableContainer(aAccessible, aAccessible->State());
     if (widget) {
       AccSelChangeEvent::SelChangeType selChangeType =
         elm->AttrValueIs(aNameSpaceID, aAttribute, nsGkAtoms::_true, eCaseMatters) ?
           AccSelChangeEvent::eSelectionAdd : AccSelChangeEvent::eSelectionRemove;
 
-      nsRefPtr<AccEvent> event =
+      RefPtr<AccEvent> event =
         new AccSelChangeEvent(widget, aAccessible, selChangeType);
       FireDelayedEvent(event);
     }
 
     return;
   }
 
   if (aAttribute == nsGkAtoms::contenteditable) {
-    nsRefPtr<AccEvent> editableChangeEvent =
+    RefPtr<AccEvent> editableChangeEvent =
       new AccStateChangeEvent(aAccessible, states::EDITABLE);
     FireDelayedEvent(editableChangeEvent);
     return;
   }
 
   if (aAttribute == nsGkAtoms::value) {
     if (aAccessible->IsProgress())
       FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible);
@@ -910,24 +949,24 @@ DocAccessible::AttributeChangedImpl(Acce
 // DocAccessible protected member
 void
 DocAccessible::ARIAAttributeChanged(Accessible* aAccessible, nsIAtom* aAttribute)
 {
   // Note: For universal/global ARIA states and properties we don't care if
   // there is an ARIA role present or not.
 
   if (aAttribute == nsGkAtoms::aria_required) {
-    nsRefPtr<AccEvent> event =
+    RefPtr<AccEvent> event =
       new AccStateChangeEvent(aAccessible, states::REQUIRED);
     FireDelayedEvent(event);
     return;
   }
 
   if (aAttribute == nsGkAtoms::aria_invalid) {
-    nsRefPtr<AccEvent> event =
+    RefPtr<AccEvent> event =
       new AccStateChangeEvent(aAccessible, states::INVALID);
     FireDelayedEvent(event);
     return;
   }
 
   // The activedescendant universal property redirects accessible focus events
   // to the element with the id that activedescendant points to. Make sure
   // the tree up to date before processing.
@@ -935,85 +974,94 @@ DocAccessible::ARIAAttributeChanged(Acce
     mNotificationController->HandleNotification<DocAccessible, Accessible>
       (this, &DocAccessible::ARIAActiveDescendantChanged, aAccessible);
 
     return;
   }
 
   // We treat aria-expanded as a global ARIA state for historical reasons
   if (aAttribute == nsGkAtoms::aria_expanded) {
-    nsRefPtr<AccEvent> event =
+    RefPtr<AccEvent> event =
       new AccStateChangeEvent(aAccessible, states::EXPANDED);
     FireDelayedEvent(event);
     return;
   }
 
   // For aria attributes like drag and drop changes we fire a generic attribute
   // change event; at least until native API comes up with a more meaningful event.
   uint8_t attrFlags = aria::AttrCharacteristicsFor(aAttribute);
   if (!(attrFlags & ATTR_BYPASSOBJ)) {
-    nsRefPtr<AccEvent> event =
+    RefPtr<AccEvent> event =
       new AccObjectAttrChangedEvent(aAccessible, aAttribute);
     FireDelayedEvent(event);
   }
 
   nsIContent* elm = aAccessible->GetContent();
 
   // Update aria-hidden flag for the whole subtree iff aria-hidden is changed
   // on the root, i.e. ignore any affiliated aria-hidden changes in the subtree
   // of top aria-hidden.
   if (aAttribute == nsGkAtoms::aria_hidden) {
     bool isDefined = aria::HasDefinedARIAHidden(elm);
     if (isDefined != aAccessible->IsARIAHidden() &&
         !aAccessible->Parent()->IsARIAHidden()) {
       aAccessible->SetARIAHidden(isDefined);
 
-      nsRefPtr<AccEvent> event =
+      RefPtr<AccEvent> event =
         new AccObjectAttrChangedEvent(aAccessible, aAttribute);
       FireDelayedEvent(event);
     }
     return;
   }
 
   if (aAttribute == nsGkAtoms::aria_checked ||
       (aAccessible->IsButton() &&
        aAttribute == nsGkAtoms::aria_pressed)) {
     const uint64_t kState = (aAttribute == nsGkAtoms::aria_checked) ?
                             states::CHECKED : states::PRESSED;
-    nsRefPtr<AccEvent> event = new AccStateChangeEvent(aAccessible, kState);
+    RefPtr<AccEvent> event = new AccStateChangeEvent(aAccessible, kState);
     FireDelayedEvent(event);
 
     bool wasMixed = (mARIAAttrOldValue == nsGkAtoms::mixed);
     bool isMixed = elm->AttrValueIs(kNameSpaceID_None, aAttribute,
                                     nsGkAtoms::mixed, eCaseMatters);
     if (isMixed != wasMixed) {
-      nsRefPtr<AccEvent> event =
+      RefPtr<AccEvent> event =
         new AccStateChangeEvent(aAccessible, states::MIXED, isMixed);
       FireDelayedEvent(event);
     }
     return;
   }
 
   if (aAttribute == nsGkAtoms::aria_readonly) {
-    nsRefPtr<AccEvent> event =
+    RefPtr<AccEvent> event =
       new AccStateChangeEvent(aAccessible, states::READONLY);
     FireDelayedEvent(event);
     return;
   }
 
-  // Fire value change event whenever aria-valuetext is changed, or
-  // when aria-valuenow is changed and aria-valuetext is empty
-  if (aAttribute == nsGkAtoms::aria_valuetext ||
-      (aAttribute == nsGkAtoms::aria_valuenow &&
-       (!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuetext) ||
-        elm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_valuetext,
-                         nsGkAtoms::_empty, eCaseMatters)))) {
+  // Fire text value change event whenever aria-valuetext is changed.
+  if (aAttribute == nsGkAtoms::aria_valuetext) {
+    FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE, aAccessible);
+    return;
+  }
+
+  // Fire numeric value change event when aria-valuenow is changed and
+  // aria-valuetext is empty
+  if (aAttribute == nsGkAtoms::aria_valuenow &&
+      (!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuetext) ||
+       elm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_valuetext,
+                        nsGkAtoms::_empty, eCaseMatters))) {
     FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible);
     return;
   }
+
+  if (aAttribute == nsGkAtoms::aria_owns) {
+    mNotificationController->ScheduleRelocation(aAccessible);
+  }
 }
 
 void
 DocAccessible::ARIAActiveDescendantChanged(Accessible* aAccessible)
 {
   nsIContent* elm = aAccessible->GetContent();
   if (elm && aAccessible->IsActiveWidget()) {
     nsAutoString id;
@@ -1052,36 +1100,36 @@ DocAccessible::ContentStateChanged(nsIDo
     return;
 
   if (aStateMask.HasState(NS_EVENT_STATE_CHECKED)) {
     Accessible* widget = accessible->ContainerWidget();
     if (widget && widget->IsSelect()) {
       AccSelChangeEvent::SelChangeType selChangeType =
         aContent->AsElement()->State().HasState(NS_EVENT_STATE_CHECKED) ?
           AccSelChangeEvent::eSelectionAdd : AccSelChangeEvent::eSelectionRemove;
-      nsRefPtr<AccEvent> event =
+      RefPtr<AccEvent> event =
         new AccSelChangeEvent(widget, accessible, selChangeType);
       FireDelayedEvent(event);
       return;
     }
 
-    nsRefPtr<AccEvent> event =
+    RefPtr<AccEvent> event =
       new AccStateChangeEvent(accessible, states::CHECKED,
                               aContent->AsElement()->State().HasState(NS_EVENT_STATE_CHECKED));
     FireDelayedEvent(event);
   }
 
   if (aStateMask.HasState(NS_EVENT_STATE_INVALID)) {
-    nsRefPtr<AccEvent> event =
+    RefPtr<AccEvent> event =
       new AccStateChangeEvent(accessible, states::INVALID, true);
     FireDelayedEvent(event);
   }
 
   if (aStateMask.HasState(NS_EVENT_STATE_VISITED)) {
-    nsRefPtr<AccEvent> event =
+    RefPtr<AccEvent> event =
       new AccStateChangeEvent(accessible, states::TRAVERSED, true);
     FireDelayedEvent(event);
   }
 }
 
 void
 DocAccessible::DocumentStatesChanged(nsIDocument* aDocument,
                                      EventStates aStateMask)
@@ -1234,19 +1282,26 @@ DocAccessible::BindToDocument(Accessible
   if (aAccessible->IsNodeMapEntry())
     mNodeToAccessibleMap.Put(aAccessible->GetNode(), aAccessible);
 
   // Put into unique ID cache.
   mAccessibleCache.Put(aAccessible->UniqueID(), aAccessible);
 
   aAccessible->SetRoleMapEntry(aRoleMapEntry);
 
-  nsIContent* content = aAccessible->GetContent();
-  if (content && content->IsElement())
-    AddDependentIDsFor(content->AsElement());
+  AddDependentIDsFor(aAccessible);
+
+  if (aAccessible->HasOwnContent()) {
+    nsIContent* el = aAccessible->GetContent();
+    if (el->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_owns)) {
+      mNotificationController->ScheduleRelocation(aAccessible);
+    }
+
+    RelocateARIAOwnedIfNeeded(el);
+  }
 }
 
 void
 DocAccessible::UnbindFromDocument(Accessible* aAccessible)
 {
   NS_ASSERTION(mAccessibleCache.GetWeak(aAccessible->UniqueID()),
                "Unbinding the unbound accessible!");
 
@@ -1358,109 +1413,73 @@ 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;
 
   if (!IsLoadEventTarget())
     return;
 
   if (aIsReloading) {
     // Fire reload and state busy events on existing document accessible while
     // event from user input flag can be calculated properly and accessible
     // is alive. When new document gets loaded then this one is destroyed.
-    nsRefPtr<AccEvent> reloadEvent =
+    RefPtr<AccEvent> reloadEvent =
       new AccEvent(nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD, this);
     nsEventShell::FireEvent(reloadEvent);
   }
 
   // Fire state busy change event. Use delayed event since we don't care
   // actually if event isn't delivered when the document goes away like a shot.
-  nsRefPtr<AccEvent> stateEvent =
+  RefPtr<AccEvent> stateEvent =
     new AccStateChangeEvent(this, states::BUSY, true);
   FireDelayedEvent(stateEvent);
 }
 
 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
   // this document may be fired prior to this reorder event. If this is
   // a problem then consider to keep event processing per tab document.
   if (!IsRoot()) {
-    nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(Parent());
+    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);
-    nsRefPtr<AccShowEvent> event = new AccShowEvent(child, child->GetContent());
+    RefPtr<AccShowEvent> event = new AccShowEvent(child);
   FireDelayedEvent(event);
   }
 }
 
 void
 DocAccessible::ProcessLoad()
 {
   mLoadState |= eCompletelyLoaded;
@@ -1476,108 +1495,120 @@ DocAccessible::ProcessLoad()
   // documents
   // b) document load event on sub documents causes screen readers to act is if
   // entire page is reloaded.
   if (!IsLoadEventTarget())
     return;
 
   // Fire complete/load stopped if the load event type is given.
   if (mLoadEventType) {
-    nsRefPtr<AccEvent> loadEvent = new AccEvent(mLoadEventType, this);
+    RefPtr<AccEvent> loadEvent = new AccEvent(mLoadEventType, this);
     FireDelayedEvent(loadEvent);
 
     mLoadEventType = 0;
   }
 
   // Fire busy state change event.
-  nsRefPtr<AccEvent> stateEvent =
+  RefPtr<AccEvent> stateEvent =
     new AccStateChangeEvent(this, states::BUSY, false);
   FireDelayedEvent(stateEvent);
 }
 
 void
-DocAccessible::AddDependentIDsFor(dom::Element* aRelProviderElm,
-                                  nsIAtom* aRelAttr)
+DocAccessible::AddDependentIDsFor(Accessible* aRelProvider, nsIAtom* aRelAttr)
 {
+  dom::Element* relProviderEl = aRelProvider->Elm();
+  if (!relProviderEl)
+    return;
+
   for (uint32_t idx = 0; idx < kRelationAttrsLen; idx++) {
     nsIAtom* relAttr = *kRelationAttrs[idx];
     if (aRelAttr && aRelAttr != relAttr)
       continue;
 
     if (relAttr == nsGkAtoms::_for) {
-      if (!aRelProviderElm->IsAnyOfHTMLElements(nsGkAtoms::label,
-                                                nsGkAtoms::output))
+      if (!relProviderEl->IsAnyOfHTMLElements(nsGkAtoms::label,
+                                               nsGkAtoms::output))
         continue;
 
     } else if (relAttr == nsGkAtoms::control) {
-      if (!aRelProviderElm->IsAnyOfXULElements(nsGkAtoms::label,
-                                               nsGkAtoms::description))
+      if (!relProviderEl->IsAnyOfXULElements(nsGkAtoms::label,
+                                              nsGkAtoms::description))
         continue;
     }
 
-    IDRefsIterator iter(this, aRelProviderElm, relAttr);
+    IDRefsIterator iter(this, relProviderEl, relAttr);
     while (true) {
       const nsDependentSubstring id = iter.NextID();
       if (id.IsEmpty())
         break;
 
       AttrRelProviderArray* providers = mDependentIDsHash.Get(id);
       if (!providers) {
         providers = new AttrRelProviderArray();
         if (providers) {
           mDependentIDsHash.Put(id, providers);
         }
       }
 
       if (providers) {
         AttrRelProvider* provider =
-          new AttrRelProvider(relAttr, aRelProviderElm);
+          new AttrRelProvider(relAttr, relProviderEl);
         if (provider) {
           providers->AppendElement(provider);
 
           // We've got here during the children caching. If the referenced
           // content is not accessible then store it to pend its container
           // children invalidation (this happens immediately after the caching
           // is finished).
           nsIContent* dependentContent = iter.GetElem(id);
-          if (dependentContent && !HasAccessible(dependentContent)) {
-            mInvalidationList.AppendElement(dependentContent);
+          if (dependentContent) {
+            if (!HasAccessible(dependentContent)) {
+              mInvalidationList.AppendElement(dependentContent);
+            }
           }
         }
       }
     }
 
     // If the relation attribute is given then we don't have anything else to
     // check.
     if (aRelAttr)
       break;
   }
+
+  // Make sure to schedule the tree update if needed.
+  mNotificationController->ScheduleProcessing();
 }
 
 void
-DocAccessible::RemoveDependentIDsFor(dom::Element* aRelProviderElm,
+DocAccessible::RemoveDependentIDsFor(Accessible* aRelProvider,
                                      nsIAtom* aRelAttr)
 {
+  dom::Element* relProviderElm = aRelProvider->Elm();
+  if (!relProviderElm)
+    return;
+
   for (uint32_t idx = 0; idx < kRelationAttrsLen; idx++) {
     nsIAtom* relAttr = *kRelationAttrs[idx];
     if (aRelAttr && aRelAttr != *kRelationAttrs[idx])
       continue;
 
-    IDRefsIterator iter(this, aRelProviderElm, relAttr);
+    IDRefsIterator iter(this, relProviderElm, relAttr);
     while (true) {
       const nsDependentSubstring id = iter.NextID();
       if (id.IsEmpty())
         break;
 
       AttrRelProviderArray* providers = mDependentIDsHash.Get(id);
       if (providers) {
         for (uint32_t jdx = 0; jdx < providers->Length(); ) {
           AttrRelProvider* provider = (*providers)[jdx];
           if (provider->mRelAttr == relAttr &&
-              provider->mContent == aRelProviderElm)
+              provider->mContent == relProviderElm)
             providers->RemoveElement(provider);
           else
             jdx++;
         }
         if (providers->Length() == 0)
           mDependentIDsHash.Remove(id);
       }
     }
@@ -1604,18 +1635,17 @@ DocAccessible::UpdateAccessibleOnAttrCha
     // Recreate the accessible when role is changed because we might require a
     // different accessible class for the new role or the accessible may expose
     // a different sets of interfaces (COM restriction).
     RecreateAccessible(aElement);
 
     return true;
   }
 
-  if (aAttribute == nsGkAtoms::href ||
-      aAttribute == nsGkAtoms::onclick) {
+  if (aAttribute == nsGkAtoms::href) {
     // Not worth the expense to ensure which namespace these are in. It doesn't
     // kill use to recreate the accessible even if the attribute was used in
     // the wrong namespace or an element that doesn't support it.
 
     // Make sure the accessible is recreated asynchronously to allow the content
     // to handle the attribute change.
     RecreateAccessible(aElement);
     return true;
@@ -1653,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;
@@ -1691,17 +1718,17 @@ DocAccessible::UpdateTreeOnInsertion(Acc
     Accessible* child = aContainer->ContentChildAt(idx);
     child->SetSurvivingInUpdate(true);
    }
 
   AutoTreeMutation mut(aContainer);
   aContainer->InvalidateChildren();
   aContainer->EnsureChildren();
 
-  nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aContainer);
+  RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aContainer);
 
   uint32_t updateFlags = eNoAccessible;
   for (uint32_t idx = 0; idx < aContainer->ContentChildCount(); idx++) {
     Accessible* child = aContainer->ContentChildAt(idx);
     if (child->IsSurvivingInUpdate()) {
       child->SetSurvivingInUpdate(false);
       continue;
     }
@@ -1721,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)
@@ -1763,50 +1784,25 @@ DocAccessible::UpdateTreeOnRemoval(Acces
     else
       logging::MsgEntry("child accessible: null");
 
     logging::MsgEnd();
   }
 #endif
 
   uint32_t updateFlags = eNoAccessible;
-  nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aContainer);
+  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);
@@ -1820,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
@@ -1840,21 +1835,21 @@ DocAccessible::UpdateTreeInternal(Access
     // the changes before our processing and we may miss some menupopup
     // events. Now we just want to be consistent in content insertion/removal
     // handling.
     if (aChild->ARIARole() == roles::MENUPOPUP)
       FireDelayedEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END, aChild);
   }
 
   // Fire show/hide event.
-  nsRefPtr<AccMutationEvent> 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.
@@ -1884,16 +1879,289 @@ DocAccessible::UpdateTreeInternal(Access
     FocusMgr()->DispatchFocusEvent(this, focusedAcc);
     SelectionMgr()->SetControlSelectionListener(focusedAcc->GetNode()->AsElement());
   }
 
   return updateFlags;
 }
 
 void
+DocAccessible::RelocateARIAOwnedIfNeeded(nsIContent* aElement)
+{
+  if (!aElement->HasID())
+    return;
+
+  AttrRelProviderArray* list =
+    mDependentIDsHash.Get(nsDependentAtomString(aElement->GetID()));
+  if (list) {
+    for (uint32_t idx = 0; idx < list->Length(); idx++) {
+      if (list->ElementAt(idx)->mRelAttr == nsGkAtoms::aria_owns) {
+        Accessible* owner = GetAccessible(list->ElementAt(idx)->mContent);
+        if (owner) {
+          mNotificationController->ScheduleRelocation(owner);
+        }
+      }
+    }
+  }
+}
+
+void
+DocAccessible::ValidateARIAOwned()
+{
+  for (auto it = mARIAOwnsHash.Iter(); !it.Done(); it.Next()) {
+    Accessible* owner = it.Key();
+    nsTArray<RefPtr<Accessible> >* children = it.UserData();
+
+    // Owner is about to die, put children back if applicable.
+    if (!mAccessibleCache.GetWeak(reinterpret_cast<void*>(owner)) ||
+        !owner->IsInDocument()) {
+      PutChildrenBack(children, 0);
+      it.Remove();
+      continue;
+    }
+
+    for (uint32_t idx = 0; idx < children->Length(); idx++) {
+      Accessible* child = children->ElementAt(idx);
+      if (!child->IsInDocument()) {
+        children->RemoveElementAt(idx);
+        idx--;
+        continue;
+      }
+
+      NS_ASSERTION(child->Parent(), "No parent for ARIA owned?");
+
+      // If DOM node doesn't have a frame anymore then shutdown its accessible.
+      if (child->Parent() && !child->GetFrame()) {
+        UpdateTreeOnRemoval(child->Parent(), child->GetContent());
+        children->RemoveElementAt(idx);
+        idx--;
+        continue;
+      }
+
+      NS_ASSERTION(child->Parent() == owner,
+                   "Illigally stolen ARIA owned child!");
+    }
+
+    if (children->Length() == 0) {
+      it.Remove();
+    }
+  }
+}
+
+void
+DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
+{
+  nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.LookupOrAdd(aOwner);
+
+  MOZ_ASSERT(aOwner, "aOwner must be a valid pointer");
+  MOZ_ASSERT(aOwner->Elm(), "aOwner->Elm() must be a valid pointer");
+
+  IDRefsIterator iter(this, aOwner->Elm(), nsGkAtoms::aria_owns);
+  Accessible* child = nullptr;
+
+  uint32_t arrayIdx = 0, insertIdx = aOwner->ChildCount() - children->Length();
+  while ((child = iter.Next())) {
+    // Same child on same position, no change.
+    if (child->Parent() == aOwner &&
+        child->IndexInParent() == static_cast<int32_t>(insertIdx)) {
+      NS_ASSERTION(child == children->ElementAt(arrayIdx), "Not in sync!");
+      insertIdx++; arrayIdx++;
+      continue;
+    }
+
+    NS_ASSERTION(children->SafeElementAt(arrayIdx) != child, "Already in place!");
+
+    nsTArray<RefPtr<Accessible> >::index_type idx = children->IndexOf(child);
+    if (idx < arrayIdx) {
+      continue; // ignore second entry of same ID
+    }
+
+    // A new child is found, check for loops.
+    if (child->Parent() != aOwner) {
+      Accessible* parent = aOwner;
+      while (parent && parent != child && !parent->IsDoc()) {
+        parent = parent->Parent();
+      }
+      // A referred child cannot be a parent of the owner.
+      if (parent == child) {
+        continue;
+      }
+    }
+
+    if (child->Parent() == aOwner) {
+      if (child->IsRelocated()) {
+        children->RemoveElement(child);
+      }
+      MoveChild(child, insertIdx);
+      children->InsertElementAt(arrayIdx, child);
+      arrayIdx++;
+      insertIdx = child->IndexInParent() + 1;
+
+    } else if (SeizeChild(aOwner, child, insertIdx)) {
+      children->InsertElementAt(arrayIdx, child);
+      insertIdx++; arrayIdx++;
+    }
+  }
+
+  // Put back children that are not seized anymore.
+  PutChildrenBack(children, arrayIdx);
+  if (children->Length() == 0) {
+    mARIAOwnsHash.Remove(aOwner);
+  }
+}
+
+bool
+DocAccessible::SeizeChild(Accessible* aNewParent, Accessible* aChild,
+                          int32_t aIdxInParent)
+{
+  Accessible* oldParent = aChild->Parent();
+  if (!oldParent) {
+    NS_ERROR("No parent? The tree is broken!");
+    return false;
+  }
+
+  int32_t oldIdxInParent = aChild->IndexInParent();
+
+#ifdef A11Y_LOG
+  logging::TreeInfo("aria owns seize child", 0,
+                    "old parent", oldParent, "new parent", aNewParent,
+                    "child", aChild, nullptr);
+#endif
+
+  RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(oldParent);
+  RefPtr<AccMutationEvent> hideEvent = new AccHideEvent(aChild, false);
+  reorderEvent->AddSubMutationEvent(hideEvent);
+
+  {
+    AutoTreeMutation mut(oldParent);
+    oldParent->RemoveChild(aChild);
+  }
+
+  bool isReinserted = false;
+  {
+    AutoTreeMutation mut(aNewParent);
+    isReinserted = aNewParent->InsertChildAt(aIdxInParent, aChild);
+  }
+
+#ifdef A11Y_LOG
+    logging::TreeInfo("aria owns seize child: new parent tree after",
+                      logging::eVerbose, aNewParent);
+#endif
+
+  if (!isReinserted) {
+    AutoTreeMutation mut(oldParent);
+    oldParent->InsertChildAt(oldIdxInParent, aChild);
+    return false;
+  }
+
+  // The child may be stolen from other ARIA owns element.
+  if (aChild->IsRelocated()) {
+    nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.Get(oldParent);
+    children->RemoveElement(aChild);
+  }
+
+  FireDelayedEvent(hideEvent);
+  MaybeNotifyOfValueChange(oldParent);
+  FireDelayedEvent(reorderEvent);
+
+  reorderEvent = new AccReorderEvent(aNewParent);
+  RefPtr<AccMutationEvent> showEvent = new AccShowEvent(aChild);
+  reorderEvent->AddSubMutationEvent(showEvent);
+
+  FireDelayedEvent(showEvent);
+  MaybeNotifyOfValueChange(aNewParent);
+  FireDelayedEvent(reorderEvent);
+
+  aChild->SetRelocated(true);
+  return true;
+}
+
+void
+DocAccessible::MoveChild(Accessible* aChild, int32_t aIdxInParent)
+{
+  NS_PRECONDITION(aChild->Parent(), "No parent?");
+
+  Accessible* parent = aChild->Parent();
+  RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(parent);
+  RefPtr<AccMutationEvent> hideEvent = new AccHideEvent(aChild, false);
+  reorderEvent->AddSubMutationEvent(hideEvent);
+
+#ifdef A11Y_LOG
+  logging::TreeInfo("aria owns move child", 0,
+                    "parent", parent, "child", aChild, nullptr);
+#endif
+
+  AutoTreeMutation mut(parent);
+  parent->MoveChild(aIdxInParent, aChild);
+  aChild->SetRelocated(true);
+
+#ifdef A11Y_LOG
+  logging::TreeInfo("aria owns move child: parent tree after",
+                    logging::eVerbose, parent);
+#endif
+
+  FireDelayedEvent(hideEvent);
+
+  RefPtr<AccMutationEvent> showEvent = new AccShowEvent(aChild);
+  reorderEvent->AddSubMutationEvent(showEvent);
+  FireDelayedEvent(showEvent);
+
+  MaybeNotifyOfValueChange(parent);
+  FireDelayedEvent(reorderEvent);
+}
+
+void
+DocAccessible::PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren,
+                               uint32_t aStartIdx)
+{
+  nsTArray<RefPtr<Accessible> > containers;
+  for (auto idx = aStartIdx; idx < aChildren->Length(); idx++) {
+    Accessible* child = aChildren->ElementAt(idx);
+
+    // If the child is in the tree then remove it from the owner.
+    if (child->IsInDocument()) {
+      Accessible* owner = child->Parent();
+      if (!owner) {
+        NS_ERROR("Cannot put the child back. No parent, a broken tree.");
+        continue;
+      }
+      RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(owner);
+      RefPtr<AccMutationEvent> hideEvent = new AccHideEvent(child, false);
+      reorderEvent->AddSubMutationEvent(hideEvent);
+      FireDelayedEvent(hideEvent);
+
+      {
+        AutoTreeMutation mut(owner);
+        owner->RemoveChild(child);
+        child->SetRelocated(false);
+      }
+
+      MaybeNotifyOfValueChange(owner);
+      FireDelayedEvent(reorderEvent);
+    }
+
+    Accessible* container = GetContainerAccessible(child->GetContent());
+    if (container &&
+        containers.IndexOf(container) == nsTArray<Accessible*>::NoIndex) {
+      containers.AppendElement(container);
+    }
+  }
+
+  // And put it back where it belongs to.
+  aChildren->RemoveElementsAt(aStartIdx, aChildren->Length() - aStartIdx);
+  for (uint32_t idx = 0; idx < containers.Length(); idx++) {
+    NS_ASSERTION(containers[idx]->IsInDocument(),
+                 "A container has been destroyed.");
+    if (containers[idx]->IsInDocument()) {
+      UpdateTreeOnInsertion(containers[idx]);
+    }
+  }
+}
+
+void
 DocAccessible::CacheChildrenInSubtree(Accessible* aRoot,
                                       Accessible** aFocusedAcc)
 {
   // If the accessible is focused then report a focus event after all related
   // mutation events.
   if (aFocusedAcc && !*aFocusedAcc &&
       FocusMgr()->HasDOMFocus(aRoot->GetContent()))
     *aFocusedAcc = aRoot;
@@ -1920,20 +2188,17 @@ DocAccessible::CacheChildrenInSubtree(Ac
       FireDelayedEvent(nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE, aRoot);
   }
 }
 
 void
 DocAccessible::UncacheChildrenInSubtree(Accessible* aRoot)
 {
   aRoot->mStateFlags |= eIsNotInDocument;
-
-  nsIContent* rootContent = aRoot->GetContent();
-  if (rootContent && rootContent->IsElement())
-    RemoveDependentIDsFor(rootContent->AsElement());
+  RemoveDependentIDsFor(aRoot);
 
   uint32_t count = aRoot->ContentChildCount();
   for (uint32_t idx = 0; idx < count; idx++)
     UncacheChildrenInSubtree(aRoot->ContentChildAt(idx));
 
   if (aRoot->IsNodeMapEntry() &&
       mNodeToAccessibleMap.Get(aRoot->GetNode()) == aRoot)
     mNodeToAccessibleMap.Remove(aRoot->GetNode());
@@ -1987,30 +2252,8 @@ DocAccessible::IsLoadEventTarget() const
     DocAccessible* parentDoc = ParentDocument();
     return parentDoc && parentDoc->HasLoadState(eCompletelyLoaded);
   }
 
   // It's content (not chrome) root document.
   return (treeItem->ItemType() == nsIDocShellTreeItem::typeContent);
 }
 
-PLDHashOperator
-DocAccessible::CycleCollectorTraverseDepIDsEntry(const nsAString& aKey,
-                                                 AttrRelProviderArray* aProviders,
-                                                 void* aUserArg)
-{
-  nsCycleCollectionTraversalCallback* cb =
-    static_cast<nsCycleCollectionTraversalCallback*>(aUserArg);
-
-  for (int32_t jdx = aProviders->Length() - 1; jdx >= 0; jdx--) {
-    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
-                                       "content of dependent ids hash entry of document accessible");
-
-    AttrRelProvider* provider = (*aProviders)[jdx];
-    cb->NoteXPCOMChild(provider->mContent);
-
-    NS_ASSERTION(provider->mContent->IsInDoc(),
-                 "Referred content is not in document!");
-  }
-
-  return PL_DHASH_NEXT;
-}
-
--- a/accessible/generic/DocAccessible.h
+++ b/accessible/generic/DocAccessible.h
@@ -27,17 +27,17 @@ const uint32_t kDefaultCacheLength = 128
 
 namespace mozilla {
 namespace a11y {
 
 class DocManager;
 class NotificationController;
 class DocAccessibleChild;
 class RelatedAccIterator;
-template<class Class, class Arg>
+template<class Class, class ... Args>
 class TNotification;
 
 class DocAccessible : public HyperTextAccessibleWrap,
                       public nsIDocumentObserver,
                       public nsIObserver,
                       public nsIScrollPositionListener,
                       public nsSupportsWeakReference,
                       public nsIAccessiblePivotObserver
@@ -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
 
@@ -277,16 +276,28 @@ public:
   }
 
   /**
    * Return an accessible for the given node or its first accessible descendant.
    */
   Accessible* GetAccessibleOrDescendant(nsINode* aNode) const;
 
   /**
+   * Returns aria-owns seized child at the given index.
+   */
+  Accessible* ARIAOwnedAt(Accessible* aParent, uint32_t aIndex) const
+  {
+    nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.Get(aParent);
+    if (children) {
+      return children->SafeElementAt(aIndex);
+    }
+    return nullptr;
+  }
+
+  /**
    * Return true if the given ID is referred by relation attribute.
    *
    * @note Different elements may share the same ID if they are hosted inside
    *       XBL bindings. Be careful the result of this method may be  senseless
    *       while it's called for XUL elements (where XBL is used widely).
    */
   bool IsDependentID(const nsAString& aID) const
     { return mDependentIDsHash.Get(aID, nullptr); }
@@ -331,24 +342,27 @@ public:
    */
   void UpdateText(nsIContent* aTextNode);
 
   /**
    * Recreate an accessible, results in hide/show events pair.
    */
   void RecreateAccessible(nsIContent* aContent);
 
+  /**
+   * If this document is in a content process return the object responsible for
+   * communicating with the main process for it.
+   */
+  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);
@@ -358,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.
    */
@@ -395,28 +414,28 @@ protected:
   /**
    * Add dependent IDs pointed by accessible element by relation attribute to
    * cache. If the relation attribute is missed then all relation attributes
    * are checked.
    *
    * @param aRelProvider [in] accessible that element has relation attribute
    * @param aRelAttr     [in, optional] relation attribute
    */
-  void AddDependentIDsFor(dom::Element* aRelProviderElm,
+  void AddDependentIDsFor(Accessible* aRelProvider,
                           nsIAtom* aRelAttr = nullptr);
 
   /**
    * Remove dependent IDs pointed by accessible element by relation attribute
    * from cache. If the relation attribute is absent then all relation
    * attributes are checked.
    *
    * @param aRelProvider [in] accessible that element has relation attribute
    * @param aRelAttr     [in, optional] relation attribute
    */
-  void RemoveDependentIDsFor(dom::Element* aRelProviderElm,
+  void RemoveDependentIDsFor(Accessible* aRelProvider,
                              nsIAtom* aRelAttr = nullptr);
 
   /**
    * Update or recreate an accessible depending on a changed attribute.
    *
    * @param aElement   [in] the element the attribute was changed on
    * @param aAttribute [in] the changed attribute
    * @return            true if an action was taken on the attribute change
@@ -481,16 +500,48 @@ protected:
     eAccessible = 1,
     eAlertAccessible = 2
   };
 
   uint32_t UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
                               AccReorderEvent* aReorderEvent);
 
   /**
+   * Schedule ARIA owned element relocation if needed.
+   */
+  void RelocateARIAOwnedIfNeeded(nsIContent* aEl);
+
+  /**
+   * Validates all aria-owns connections and updates the tree accordingly.
+   */
+  void ValidateARIAOwned();
+
+  /**
+   * Steals or puts back accessible subtrees.
+   */
+  void DoARIAOwnsRelocation(Accessible* aOwner);
+
+  /**
+   * Moves the child from old parent under new one.
+   */
+  bool SeizeChild(Accessible* aNewParent, Accessible* aChild,
+                  int32_t aIdxInParent);
+
+  /**
+   * Move the child under same parent.
+   */
+  void MoveChild(Accessible* aChild, int32_t aIdxInParent);
+
+  /**
+   * Moves children back under their original parents.
+   */
+  void PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren,
+                       uint32_t aStartIdx);
+
+  /**
    * Create accessible tree.
    *
    * @param aRoot       [in] a root of subtree to create
    * @param aFocusedAcc [in, optional] a focused accessible under created
    *                      subtree if any
    */
   void CacheChildrenInSubtree(Accessible* aRoot,
                               Accessible** aFocusedAcc = nullptr);
@@ -514,22 +565,16 @@ protected:
    *
    * Rules: The root chrome document accessible is never an event target
    * (for example, Firefox UI window). If the sub document is loaded within its
    * parent document then the parent document is a target only (aka events
    * coalescence).
    */
   bool IsLoadEventTarget() const;
 
-  /**
-   * If this document is in a content process return the object responsible for
-   * communicating with the main process for it.
-   */
-  DocAccessibleChild* IPCDoc() const { return mIPCDoc; }
-
   /*
    * Set the object responsible for communicating with the main process on
    * behalf of this document.
    */
   void SetIPCDoc(DocAccessibleChild* aIPCDoc) { mIPCDoc = aIPCDoc; }
 
   friend class DocAccessibleChild;
 
@@ -592,22 +637,22 @@ protected:
   union {
     // ARIA attribute value
     nsIAtom* mARIAAttrOldValue;
 
     // True if the accessible state bit was on
     bool mStateBitWasOn;
   };
 
-  nsTArray<nsRefPtr<DocAccessible> > mChildDocuments;
+  nsTArray<RefPtr<DocAccessible> > mChildDocuments;
 
   /**
    * The virtual cursor of the document.
    */
-  nsRefPtr<nsAccessiblePivot> mVirtualCursor;
+  RefPtr<nsAccessiblePivot> mVirtualCursor;
 
   /**
    * A storage class for pairing content with one of its relation attributes.
    */
   class AttrRelProvider
   {
   public:
     AttrRelProvider(nsIAtom* aRelAttr, nsIContent* aContent) :
@@ -617,44 +662,43 @@ protected:
     nsCOMPtr<nsIContent> mContent;
 
   private:
     AttrRelProvider();
     AttrRelProvider(const AttrRelProvider&);
     AttrRelProvider& operator =(const AttrRelProvider&);
   };
 
-  typedef nsTArray<nsAutoPtr<AttrRelProvider> > AttrRelProviderArray;
-  typedef nsClassHashtable<nsStringHashKey, AttrRelProviderArray>
-    DependentIDsHashtable;
-
   /**
    * The cache of IDs pointed by relation attributes.
    */
-  DependentIDsHashtable mDependentIDsHash;
-
-  static PLDHashOperator
-    CycleCollectorTraverseDepIDsEntry(const nsAString& aKey,
-                                      AttrRelProviderArray* aProviders,
-                                      void* aUserArg);
+  typedef nsTArray<nsAutoPtr<AttrRelProvider> > AttrRelProviderArray;
+  nsClassHashtable<nsStringHashKey, AttrRelProviderArray>
+    mDependentIDsHash;
 
   friend class RelatedAccIterator;
 
   /**
    * Used for our caching algorithm. We store the list of nodes that should be
    * invalidated.
    *
    * @see ProcessInvalidationList
    */
   nsTArray<nsIContent*> mInvalidationList;
 
   /**
+   * Holds a list of aria-owns relocations.
+   */
+  nsClassHashtable<nsPtrHashKey<Accessible>, nsTArray<RefPtr<Accessible> > >
+    mARIAOwnsHash;
+
+  /**
    * Used to process notification from core and accessible events.
    */
-  nsRefPtr<NotificationController> mNotificationController;
+  RefPtr<NotificationController> mNotificationController;
   friend class EventQueue;
   friend class NotificationController;
 
 private:
 
   nsIPresShell* mPresShell;
 
   // Exclusively owned by IPDL so don't manually delete it!
--- a/accessible/generic/HyperTextAccessible-inl.h
+++ b/accessible/generic/HyperTextAccessible-inl.h
@@ -148,32 +148,32 @@ HyperTextAccessible::AdjustCaretOffset(u
     return aOffset - 1;
 
   return aOffset;
 }
 
 inline bool
 HyperTextAccessible::IsCaretAtEndOfLine() const
 {
-  nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
+  RefPtr<nsFrameSelection> frameSelection = FrameSelection();
   return frameSelection &&
     frameSelection->GetHint() == CARET_ASSOCIATE_BEFORE;
 }
 
 inline already_AddRefed<nsFrameSelection>
 HyperTextAccessible::FrameSelection() const
 {
   nsIFrame* frame = GetFrame();
   return frame ? frame->GetFrameSelection() : nullptr;
 }
 
 inline dom::Selection*
 HyperTextAccessible::DOMSelection() const
 {
-  nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
+  RefPtr<nsFrameSelection> frameSelection = FrameSelection();
   return frameSelection ?
     frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL) :
     nullptr;
 }
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/generic/HyperTextAccessible.cpp
+++ b/accessible/generic/HyperTextAccessible.cpp
@@ -25,16 +25,17 @@
 #include "nsContainerFrame.h"
 #include "nsFrameSelection.h"
 #include "nsILineIterator.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIPersistentProperties2.h"
 #include "nsIScrollableFrame.h"
 #include "nsIServiceManager.h"
 #include "nsITextControlElement.h"
+#include "nsIMathMLFrame.h"
 #include "nsTextFragment.h"
 #include "mozilla/BinarySearch.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/MathAlgorithms.h"
 #include "gfxSkipChars.h"
 #include <algorithm>
@@ -278,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);
 }
@@ -402,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)))
-