Merge review head draft
authorGregory Szorc <gps@mozilla.com>
Fri, 24 Mar 2017 14:54:24 -0700
changeset 541643 b86e9211df3d8b800d9e8321d2851ebd00e58636
parent 541642 eea795a9552278d6d596e48597af44e8c95c9afe (diff)
parent 458420 64cc445c5e16516f1b7dc22f538c4a4fddf6b2e4 (current diff)
child 541644 fed6d30767d181c91e27e87cdee6d5535c1699aa
push id50959
push usergszorc@mozilla.com
push dateFri, 24 Mar 2017 21:58:24 +0000
milestone55.0a1
Merge review head
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -1,12 +1,18 @@
 ^build/clang-plugin/tests/.*
 ^config/gcc-stl-wrapper.template.h
 ^config/msvc-stl-wrapper.template.h
 ^js/src/jsapi-tests/.*
+^widget/android/GeneratedJNINatives.h
+^widget/android/GeneratedJNIWrappers.cpp
+^widget/android/GeneratedJNIWrappers.h
+^widget/android/fennec/FennecJNINatives.h
+^widget/android/fennec/FennecJNIWrappers.cpp
+^widget/android/fennec/FennecJNIWrappers.h
 
 # Generated from ./tools/rewriting/ThirdPartyPaths.txt
 # awk '{print "^"$1".*"}' ./tools/rewriting/ThirdPartyPaths.txt
 ^browser/components/translation/cld2/.*
 ^build/stlport/.*
 ^db/sqlite3/src/.*
 ^dom/media/platforms/ffmpeg/libav.*
 ^extensions/spellcheck/hunspell/src/.*
@@ -14,57 +20,63 @@
 ^gfx/2d/image_operations.*
 ^gfx/angle/.*
 ^gfx/cairo/.*
 ^gfx/graphite2/.*
 ^gfx/harfbuzz/.*
 ^gfx/ots/.*
 ^gfx/qcms/.*
 ^gfx/skia/.*
+^gfx/webrender.*
+^gfx/webrender_traits.*
 ^gfx/ycbcr/.*
 ^intl/hyphenation/hyphen/.*
 ^intl/icu/.*
 ^ipc/chromium/.*
 ^js/src/ctypes/libffi/.*
 ^js/src/dtoa.c.*
 ^js/src/jit/arm64/vixl/.*
 ^media/gmp-clearkey/0.1/openaes/.*
 ^media/kiss_fft/.*
+^media/ffvpx/.*
 ^media/libav/.*
 ^media/libcubeb/.*
 ^media/libjpeg/.*
 ^media/libmkv/.*
 ^media/libnestegg/.*
 ^media/libogg/.*
 ^media/libopus/.*
 ^media/libpng/.*
 ^media/libsoundtouch/.*
 ^media/libspeex_resampler/.*
 ^media/libstagefright/.*
 ^media/libtheora/.*
 ^media/libtremor/.*
 ^media/libvorbis/.*
 ^media/libvpx/.*
 ^media/libyuv/.*
-^media/mtransport/.*
+^media/mtransport/third_party/.*
 ^media/openmax_dl/.*
 ^media/pocketsphinx/.*
 ^media/sphinxbase/.*
 ^media/webrtc/trunk/.*
+^media/webrtc/signaling/src/sdp/sipcc/.*
 ^memory/jemalloc/src/.*
 ^mfbt/decimal/.*
-^mfbt/double-conversion/.*
+^mfbt/double-conversion/source/.*
 ^mfbt/lz4.*
 ^mobile/android/thirdparty/.*
 ^modules/brotli/.*
+^modules/fdlibm/.*
 ^modules/freetype2/.*
 ^modules/libbz2/.*
 ^modules/libmar/.*
 ^modules/zlib/.*
 ^netwerk/sctp/src/.*
 ^netwerk/srtp/src/.*
 ^nsprpub/.*
 ^other-licenses/.*
+^parser/expat/.*
 ^security/sandbox/chromium/.*
 ^testing/gtest/gmock/.*
 ^testing/gtest/gtest/.*
 ^toolkit/components/protobuf/.*
 ^toolkit/crashreporter/google-breakpad/.*
new file mode 100644
--- /dev/null
+++ b/.cron.yml
@@ -0,0 +1,61 @@
+# Definitions for jobs that run periodically.  For details on the format, see
+# `taskcluster/taskgraph/cron/schema.py`.  For documentation, see
+# `taskcluster/docs/cron.rst`.
+
+jobs:
+    - name: nightly-desktop
+      job:
+          type: decision-task
+          treeherder-symbol: Nd
+          triggered-by: nightly
+          target-tasks-method: nightly_linux
+      run-on-projects:
+          - mozilla-central
+          - mozilla-aurora
+          - date
+      when:
+          by-project:
+            # Match buildbot starts for now
+            date: [{hour: 16, minute: 0}]
+            mozilla-central: [{hour: 11, minute: 0}]
+            mozilla-aurora: [{hour: 8, minute: 45}]  # Buildbot uses minute 40
+            # No default
+
+    - name: nightly-android
+      job:
+          type: decision-task
+          treeherder-symbol: Na
+          triggered-by: nightly
+          target-tasks-method: nightly_fennec
+      run-on-projects:
+          - mozilla-central
+          - mozilla-aurora
+          - date
+      when:
+        by-project:
+            # Match buildbot starts for now
+            date: [{hour: 16, minute: 0}]
+            mozilla-central: [{hour: 11, minute: 0}]
+            mozilla-aurora: [{hour: 8, minute: 45}]  # Buildbot uses minute 40
+            # No default
+
+    - name: nightly-mochitest-valgrind
+      job:
+          type: decision-task
+          treeherder-symbol: Vg
+          target-tasks-method: mochitest_valgrind
+      run-on-projects:
+          - mozilla-central
+      when:
+          - {hour: 16, minute: 0}
+          - {hour: 4, minute: 0}
+
+    - name: nightly-code-coverage
+      job:
+          type: decision-task
+          treeherder-symbol: Nc
+          target-tasks-method: nightly_code_coverage
+      run-on-projects:
+          - mozilla-central
+      when:
+          - {hour: 18, minute: 0}
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,48 +1,47 @@
 # Always ignore node_modules.
 **/node_modules/**/*.*
 
 # Exclude expected objdirs.
 obj*/**
 
 # We ignore all these directories by default, until we get them enabled.
 # If you are enabling a directory, please add directory specific exclusions
-# below.
+# below.
 addon-sdk/**
 build/**
 caps/**
 chrome/**
 config/**
 db/**
 docshell/**
-dom/**
 editor/**
 embedding/**
 extensions/**
 gfx/**
 gradle/**
 hal/**
 image/**
 intl/**
 ipc/**
-js/**
 layout/**
 media/**
 memory/**
 mfbt/**
 modules/**
 mozglue/**
 netwerk/**
 nsprpub/**
 other-licenses/**
 parser/**
 probes/**
 python/**
 rdf/**
+servo/**
 startupcache/**
 testing/**
 tools/update-packaging/**
 uriloader/**
 view/**
 widget/**
 xpcom/**
 xpfe/**
@@ -51,79 +50,97 @@ 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/branding/**/firefox-branding.js
-browser/base/content/browser-social.js
 browser/base/content/nsContextMenu.js
 browser/base/content/sanitizeDialog.js
 browser/base/content/test/general/file_csp_block_all_mixedcontent.html
 browser/base/content/test/urlbar/file_blank_but_not_blank.html
 browser/base/content/newtab/**
 browser/components/downloads/**
-browser/components/privatebrowsing/**
-browser/components/sessionstore/**
+# Test files that are really json not js, and don't need to be linted.
+browser/components/sessionstore/test/unit/data/sessionstore_valid.js
+browser/components/sessionstore/test/unit/data/sessionstore_invalid.js
 browser/components/tabview/**
-# generated files in cld2
-browser/components/translation/cld2/cld-worker.js
-browser/extensions/pdfjs/**
+# generated & special files in cld2
+browser/components/translation/cld2/**
+browser/extensions/pdfjs/content/build**
+browser/extensions/pdfjs/content/web**
 # generated or library files in pocket
 browser/extensions/pocket/content/panels/js/tmpl.js
 browser/extensions/pocket/content/panels/js/vendor/**
 browser/locales/**
 # imported from chromium
 browser/extensions/mortar/**
 
 # devtools/ exclusions
 devtools/client/canvasdebugger/**
 devtools/client/commandline/**
 devtools/client/debugger/**
 devtools/client/framework/**
 !devtools/client/framework/selection.js
-!devtools/client/framework/toolbox.js
-devtools/client/netmonitor/test/**
-devtools/client/netmonitor/har/test/**
+!devtools/client/framework/target*
+!devtools/client/framework/toolbox*
+devtools/client/inspector/markup/test/doc_markup_events_*.html
+devtools/client/inspector/rules/test/doc_media_queries.html
+devtools/client/memory/test/chrome/*.html
+devtools/client/performance/components/test/test_jit_optimizations_01.html
 devtools/client/projecteditor/**
+devtools/client/responsive.html/test/browser/touch.html
 devtools/client/responsivedesign/**
+!devtools/client/responsivedesign/responsivedesign.jsm
 devtools/client/scratchpad/**
 devtools/client/shadereditor/**
 devtools/client/shared/*.jsm
+devtools/client/shared/components/reps/reps.js
+devtools/client/shared/components/reps/test/mochitest/*.html
+!devtools/client/shared/components/reps/test/mochitest/test_reps_infinity.html
+!devtools/client/shared/components/reps/test/mochitest/test_reps_nan.html
+!devtools/client/shared/components/reps/test/mochitest/test_reps_promise.html
+!devtools/client/shared/components/reps/test/mochitest/test_reps_symbol.html
+!devtools/client/shared/components/reps/test/mochitest/test_reps_text-node.html
+devtools/client/shared/components/test/mochitest/*.html
+!devtools/client/shared/components/test/mochitest/test_stack-trace.html
+devtools/client/shared/shim/test/test_*.html
+devtools/client/shared/test/browser_toolbar_webconsole_errors_count.html
 devtools/client/shared/webgl-utils.js
 devtools/client/shared/widgets/*.jsm
+devtools/client/storage/test/*.html
+!devtools/client/storage/test/storage-cookies.html
+!devtools/client/storage/test/storage-overflow.html
+!devtools/client/storage/test/storage-search.html
+!devtools/client/storage/test/storage-unsecured-iframe.html
+!devtools/client/storage/test/storage-unsecured-iframe-usercontextid.html
 devtools/client/webaudioeditor/**
 devtools/client/webconsole/net/**
 devtools/client/webconsole/test/**
 devtools/client/webconsole/console-output.js
 devtools/client/webconsole/hudservice.js
-devtools/client/webconsole/utils.js
 devtools/client/webconsole/webconsole-connection-proxy.js
 devtools/client/webconsole/webconsole.js
 devtools/client/webide/**
 !devtools/client/webide/components/webideCli.js
-devtools/server/actors/*.js
-!devtools/server/actors/csscoverage.js
-!devtools/server/actors/inspector.js
-!devtools/server/actors/layout.js
-!devtools/server/actors/string.js
-!devtools/server/actors/styles.js
-!devtools/server/actors/tab.js
-!devtools/server/actors/webbrowser.js
-!devtools/server/actors/webextension.js
-!devtools/server/actors/webextension-inspected-window.js
-devtools/server/tests/browser/**
-!devtools/server/tests/browser/browser_webextension_inspected_window.js
-devtools/server/tests/mochitest/**
-devtools/server/tests/unit/**
-devtools/shared/heapsnapshot/**
-devtools/shared/transport/tests/unit/**
-devtools/shared/webconsole/test/**
+devtools/server/actors/webconsole.js
+devtools/server/actors/object.js
+devtools/server/actors/script.js
+devtools/server/actors/styleeditor.js
+devtools/server/actors/stylesheets.js
+devtools/server/tests/browser/storage-*.html
+!devtools/server/tests/browser/storage-unsecured-iframe.html
+devtools/server/tests/browser/stylesheets-nested-iframes.html
+devtools/server/tests/unit/xpcshell_debugging_script.js
+devtools/shared/platform/content/test/test_clipboard.html
+devtools/shared/qrcode/tests/mochitest/test_decode.html
+devtools/shared/tests/mochitest/*.html
+devtools/shared/webconsole/test/test_*.html
 
 # Ignore devtools pre-processed files
 devtools/client/framework/toolbox-process-window.js
 devtools/client/performance/system.js
 devtools/client/webide/webide-prefs.js
 devtools/client/preferences/**
 
 # Ignore devtools third-party libs
@@ -132,16 +149,17 @@ devtools/shared/acorn/*
 devtools/shared/gcli/source/*
 devtools/shared/node-properties/*
 devtools/shared/pretty-fast/*
 devtools/shared/sourcemap/*
 devtools/shared/sprintfjs/*
 devtools/shared/qrcode/decoder/*
 devtools/shared/qrcode/encoder/*
 devtools/client/shared/demangle.js
+devtools/client/shared/source-map/*
 devtools/client/shared/vendor/*
 devtools/client/sourceeditor/codemirror/*.js
 devtools/client/sourceeditor/codemirror/**/*.js
 devtools/client/sourceeditor/tern/*
 devtools/client/sourceeditor/test/cm_mode_ruby.js
 devtools/client/sourceeditor/test/codemirror/*
 devtools/client/inspector/markup/test/lib_*
 devtools/client/jsonview/lib/require.js
@@ -151,16 +169,99 @@ devtools/server/actors/utils/automation-
 devtools/client/debugger/test/mochitest/code_binary_search.js
 devtools/client/debugger/test/mochitest/code_math.min.js
 devtools/client/debugger/test/mochitest/code_math_bogus_map.js
 devtools/client/debugger/test/mochitest/code_ugly*
 devtools/client/debugger/test/mochitest/code_worker-source-map.js
 devtools/client/framework/test/code_ugly*
 devtools/server/tests/unit/babel_and_browserify_script_with_source_map.js
 devtools/server/tests/unit/setBreakpoint*
+devtools/server/tests/unit/sourcemapped.js
+
+# dom/ exclusions
+dom/animation/**
+dom/archivereader/**
+dom/asmjscache/**
+dom/audiochannel/**
+dom/base/**
+dom/battery/**
+dom/bindings/**
+dom/broadcastchannel/**
+dom/browser-element/**
+dom/cache/**
+dom/canvas/**
+dom/commandhandler/**
+dom/console/**
+dom/crypto/**
+dom/devicestorage/**
+dom/encoding/**
+dom/events/**
+dom/fetch/**
+dom/file/**
+dom/filehandle/**
+dom/filesystem/**
+dom/flyweb/**
+dom/gamepad/**
+dom/geolocation/**
+dom/grid/**
+dom/html/**
+dom/imptests/**
+dom/interfaces/**
+dom/ipc/**
+dom/json/**
+dom/jsurl/**
+dom/locales/**
+dom/manifest/**
+dom/mathml/**
+dom/media/**
+dom/messagechannel/**
+dom/network/**
+dom/notification/**
+dom/offline/**
+dom/performance/**
+dom/permission/**
+dom/plugins/**
+dom/power/**
+dom/presentation/**
+dom/promise/**
+dom/push/**
+dom/quota/**
+dom/res/**
+dom/secureelement/**
+dom/security/**
+dom/smil/**
+dom/storage/**
+dom/svg/**
+dom/system/**
+dom/tests/**
+dom/time/**
+dom/u2f/**
+dom/url/**
+dom/vr/**
+dom/webauthn/**
+dom/webbrowserpersist/**
+dom/webidl/**
+dom/workers/**
+dom/worklet/**
+dom/xbl/**
+dom/xhr/**
+dom/xml/**
+dom/xslt/**
+dom/xul/**
+
+# Exclude everything but self-hosted JS
+js/ductwork/**
+js/examples/**
+js/ipc/**
+js/public/**
+js/xpconnect/**
+js/src/devtools/**
+js/src/octane/**
+js/src/jit-test/**
+js/src/tests/**
 
 # mobile/android/ exclusions
 mobile/android/tests/
 
 # Uses `#filter substitution`
 mobile/android/b2gdroid/app/b2gdroid.js
 mobile/android/app/mobile.js
 mobile/android/chrome/content/healthreport-prefs.js
@@ -174,20 +275,32 @@ mobile/android/locales/
 
 # Non-standard `(catch ex if ...)`
 mobile/android/chrome/content/browser.js
 mobile/android/components/Snippets.js
 
 # Bug 1178739: Ignore this file as a quick fix for "Illegal yield expression"
 mobile/android/modules/HomeProvider.jsm
 
+# security/ exclusions (pref files).
+security/manager/ssl/security-prefs.js
+
+#NSS
+security/nss/**
+
 # services/ exclusions
 
 # Uses `#filter substitution`
 services/sync/modules/constants.js
+services/sync/services-sync.js
+
+# Third party services
+services/common/kinto-http-client.js
+services/common/kinto-offline-client.js
+services/sync/tps/extensions/mozmill
 
 # toolkit/ exclusions
 
 # Not part of the default build
 toolkit/components/help/**
 
 # Intentionally invalid JS
 toolkit/components/workerloader/tests/moduleF-syntax-error.js
@@ -195,28 +308,25 @@ toolkit/components/workerloader/tests/mo
 # Tests old non-star function generators
 toolkit/modules/tests/xpcshell/test_task.js
 
 # Not yet updated
 toolkit/components/osfile/**
 
 # External code:
 toolkit/components/microformats/test/**
+toolkit/components/microformats/microformat-shiv.js
 toolkit/components/reader/Readability.js
 toolkit/components/reader/JSDOMParser.js
 
 # Uses preprocessing
 toolkit/content/widgets/wizard.xml
 toolkit/components/jsdownloads/src/DownloadIntegration.jsm
 toolkit/components/url-classifier/**
 toolkit/components/urlformatter/nsURLFormatter.js
-toolkit/identity/FirefoxAccounts.jsm
 toolkit/modules/AppConstants.jsm
 toolkit/mozapps/downloads/nsHelperAppDlg.js
 toolkit/mozapps/extensions/internal/AddonConstants.jsm
 toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
 toolkit/webapps/**
 
 # Third party
 toolkit/modules/third_party/**
-
-#NSS
-security/nss/**
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,18 +1,24 @@
 "use strict";
 
 module.exports = {
   // When adding items to this file please check for effects on sub-directories.
   "plugins": [
     "mozilla"
   ],
   "rules": {
+    "mozilla/avoid-removeChild": "error",
+    "mozilla/avoid-nsISupportsString-preferences": "error",
     "mozilla/import-globals": "warn",
     "mozilla/no-import-into-var-and-global": "error",
+    "mozilla/no-useless-parameters": "error",
+    "mozilla/no-useless-removeEventListener": "error",
+    "mozilla/use-default-preference-values": "error",
+    "mozilla/use-ownerGlobal": "error",
 
     // No (!foo in bar) or (!object instanceof Class)
     "no-unsafe-negation": "error",
   },
   "env": {
     "es6": true
   },
   "parserOptions": {
--- a/.hgignore
+++ b/.hgignore
@@ -39,16 +39,18 @@
 
 # SpiderMonkey configury
 ^js/src/configure$
 ^js/src/old-configure$
 ^js/src/autom4te.cache$
 # SpiderMonkey test result logs
 ^js/src/tests/results-.*\.(html|txt)$
 ^js/src/devtools/rootAnalysis/t/out
+# SpiderMonkey clone of the webassembly spec repository
+^js/src/wasm/spec
 
 # Java HTML5 parser classes
 ^parser/html/java/(html|java)parser/
 
 # SVN directories
 \.svn/
 
 # Ignore the files and directory that Eclipse IDE creates
@@ -129,8 +131,11 @@ GPATH
 ^testing/talos/talos/tests/devtools/damp.manifest.develop
 ^talos-venv
 
 # Ignore files created when running a reftest.
 ^lextab.py$
 
 # tup database
 ^\.tup
+
+subinclude:servo/.hgignore
+
--- a/.hgtags
+++ b/.hgtags
@@ -125,8 +125,10 @@ 67a788db9f07822cfef52351bbbe3745dff8bd7f
 99137d6d4061f408ae0869122649d8bdf489cc30 FIREFOX_AURORA_45_BASE
 67c66c2878aed17ae3096d7db483ddbb2293c503 FIREFOX_AURORA_46_BASE
 68d3781deda0d4d58ec9877862830db89669b3a5 FIREFOX_AURORA_47_BASE
 1c6385ae1fe7e37d8f23f958ce14582f07af729e FIREFOX_AURORA_48_BASE
 d98f20c25feeac4dd7ebbd1c022957df1ef58af4 FIREFOX_AURORA_49_BASE
 465d150bc8be5bbf9f02a8607d4552b6a5e1697c FIREFOX_AURORA_50_BASE
 fc69febcbf6c0dcc4b3dfc7a346d8d348798a65f FIREFOX_AURORA_51_BASE
 1196bf3032e1bce1fb07a01fd9082a767426c5fb FIREFOX_AURORA_52_BASE
+f80dc9fc34680105b714a49b4704bb843f5f7004 FIREFOX_AURORA_53_BASE
+6583496f169cd8a13c531ed16e98e8bf313eda8e FIREFOX_AURORA_54_BASE
--- a/.taskcluster.yml
+++ b/.taskcluster.yml
@@ -8,33 +8,39 @@ metadata:
 
 scopes:
   # Note the below scopes are insecure however these get overriden on the server
   # side to whatever scopes are set by mozilla-taskcluster.
   - queue:*
   - docker-worker:*
   - scheduler:*
 
-# Available mustache parameters (see the mozilla-taskcluster source):
+# This file undergoes substitution to create tasks.  For on-push tasks, that
+# substitution is done by mozilla-taskcluster.  For cron tasks, that substitution
+# is done by `taskcluster/taskgraph/cron/decision.py`.  If you change any of the
+# template parameters, please do so in all three places!
 #
+# Available template parameters:
+#
+# - now:            current time
 # - owner:          push user (email address)
 # - source:         URL of this YAML file
 # - url:            repository URL
 # - project:        alias for the destination repository (basename of
 #                   the repo url)
 # - level:          SCM level of the destination repository
 #                   (1 = try, 3 = core)
-# - revision:       (short) hg revision of the head of the push
-# - revision_hash:  (long) hg revision of the head of the push
+# - revision:       hg revision of the head of the push
 # - comment:        comment of the push
 # - pushlog_id:     id in the pushlog table of the repository
 #
 # and functions:
 # - as_slugid:      convert a label into a slugId
 # - from_now:       generate a timestamp at a fixed offset from now
+# - shellquote:     quote the contents for injection into shell
 
 # The resulting tasks' taskGroupId will be equal to the taskId of the first
 # task listed here, which should be the decision task.  This gives other tools
 # an easy way to determine the ID of the decision task that created a
 # particular group.
 
 tasks:
   - taskId: '{{#as_slugid}}decision task{{/as_slugid}}'
@@ -74,17 +80,17 @@ tasks:
           level-{{level}}-checkouts: /home/worker/checkouts
 
         features:
           taskclusterProxy: true
           chainOfTrust: true
 
         # Note: This task is built server side without the context or tooling that
         # exist in tree so we must hard code the hash
-        image: 'taskcluster/decision@sha256:0f59f922d86c471e208b7ea08ab077fc68c3920ed5e6895d69a23e8f3457dc24'
+        image: 'taskcluster/decision:0.1.8@sha256:195d8439c8e90d59311d877bd2a8964849b2e43bfc6c234092618518d8b2891b'
 
         maxRunTime: 1800
 
         # TODO use mozilla-unified for the base repository once the tc-vcs
         # tar.gz archives are created or tc-vcs isn't being used.
         command:
           - /home/worker/bin/run-task
           - '--vcs-checkout=/home/worker/checkouts/gecko'
@@ -100,17 +106,16 @@ tasks:
               --project='{{project}}'
               --message={{#shellquote}}{{{comment}}}{{/shellquote}}
               --owner='{{owner}}'
               --level='{{level}}'
               --base-repository='https://hg.mozilla.org/mozilla-central'
               --head-repository='{{{url}}}'
               --head-ref='{{revision}}'
               --head-rev='{{revision}}'
-              --revision-hash='{{revision_hash}}'
 
         artifacts:
           'public':
             type: 'directory'
             path: '/home/worker/artifacts'
             expires: '{{#from_now}}364 days{{/from_now}}'
 
       extra:
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1250356 Setting CLOBBER out caution landing a huge patchset with gyp changes
+Bug 1343682 - backing out a previous version didn't stop the failures from it, so it appears to need a clobber both out and in
--- a/Makefile.in
+++ b/Makefile.in
@@ -91,47 +91,21 @@ config.status js/src/config.status:
 # The mach build driver will ensure the backend is up to date for partial tree
 # builds. This cleanly avoids most of the pain.
 
 ifndef TEST_MOZBUILD
 
 .PHONY: backend
 backend: $(BUILD_BACKEND_FILES)
 
-# A traditional rule would look like this:
-#    backend.%:
-#        @echo do stuff
-#
-# But with -j<n>, and multiple items in BUILD_BACKEND_FILES, the command would
-# run multiple times in parallel.
-#
-# "Fortunately", make has some weird semantics for pattern rules: if there are
-# multiple targets in a pattern rule and each of them is matched at most once,
-# the command will only run once. So:
-#     backend%RecursiveMakeBackend backend%FasterMakeBackend:
-#         @echo do stuff
-#     backend: backend.RecursiveMakeBackend backend.FasterMakeBackend
-# would only execute the command once.
-#
-# Credit where due: http://stackoverflow.com/questions/2973445/gnu-makefile-rule-generating-a-few-targets-from-a-single-source-file/3077254#3077254
-$(subst .,%,$(BUILD_BACKEND_FILES)):
-	@echo 'Build configuration changed. Regenerating backend.'
-	$(PYTHON) config.status
+include $(topsrcdir)/build/rebuild-backend.mk
 
 Makefile: $(BUILD_BACKEND_FILES)
 	@$(TOUCH) $@
 
-define build_backend_rule
-$(1)_files := $$(shell cat $(1).in)
-$(1): $$($(1)_files)
-$$($(1)_files):
-
-endef
-$(foreach file,$(BUILD_BACKEND_FILES),$(eval $(call build_backend_rule,$(file))))
-
 default:: $(BUILD_BACKEND_FILES)
 endif
 
 install_manifests := \
   $(addprefix dist/,branding idl include public private sdk xpi-stage) \
   _tests \
   $(NULL)
 # Skip the dist/bin install manifest when using the hybrid
@@ -185,37 +159,38 @@ tup:
 # js as standalone because automated builds are building nspr separately and
 # that would remove the resulting files.
 # Eventually, a standalone js build would just be able to build nspr itself,
 # removing the need for the former.
 ifdef JS_STANDALONE
 NO_REMOVE=1
 endif
 
+# For an artifact build, _tests will already be partly populated, so run
+# this install manifest with NO_REMOVE set in this case.
+ifdef MOZ_ARTIFACT_BUILDS
+install-_tests: NO_REMOVE=1
+endif
+
 .PHONY: $(addprefix install-,$(subst /,_,$(install_manifests)))
 $(addprefix install-,$(install_manifests)): install-%: $(install_manifest_depends)
 ifneq (,$(filter FasterMake+RecursiveMake,$(BUILD_BACKENDS)))
 	@# If we're using the hybrid FasterMake/RecursiveMake backend, we want
 	@# to ensure the FasterMake end doesn't have install manifests for the
 	@# same directory, because that would blow up
 	$(if $(wildcard _build_manifests/install/$(subst /,_,$*)),$(if $(wildcard faster/install_$(subst /,_,$*)*),$(error FasterMake and RecursiveMake ends of the hybrid build system want to handle $*)))
 endif
 	$(addprefix $(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )$*) ,$(wildcard _build_manifests/install/$(subst /,_,$*)))
 
 # Dummy wrapper rule to allow the faster backend to piggy back
 $(addprefix install-,$(subst /,_,$(filter dist/%,$(install_manifests)))): install-dist_%: install-dist/% ;
 
 .PHONY: install-tests
 install-tests: install-test-files
 
-# We no longer run "make install-tests" directly before running tests, but we still
-# want to depend on things like config.status, hence this target.
-.PHONY: run-tests-deps
-run-tests-deps: $(install_manifest_depends)
-
 # Force --no-remove, because $objdir/_tests is handled by multiple manifests.
 .PHONY: install-test-files
 install-test-files:
 	$(call py_action,process_install_manifest,--no-remove _tests _build_manifests/install/_test_files)
 
 include $(topsrcdir)/build/moz-automation.mk
 
 # dist and _tests should be purged during cleaning. However, we don't want them
@@ -284,23 +259,18 @@ DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_s
 else
 DUMP_SYMS_BIN ?= $(topsrcdir)/toolkit/crashreporter/tools/win32/dump_syms_vc$(_MSC_VER).exe
 endif
 # PDB files don't get moved to dist, so we need to scan the whole objdir
 MAKE_SYM_STORE_PATH := .
 endif
 ifeq ($(OS_ARCH),Darwin)
 # need to pass arch flags for universal builds
-ifdef UNIVERSAL_BINARY
-MAKE_SYM_STORE_ARGS := -c --vcs-info
-MAKE_SYM_STORE_PATH := $(DIST)/bin $(UNIFY_DIST)/bin
-else
 MAKE_SYM_STORE_ARGS := -c -a $(OS_TEST) --vcs-info
 MAKE_SYM_STORE_PATH := $(DIST)/bin
-endif
 DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
 endif
 ifeq (,$(filter-out Linux SunOS,$(OS_ARCH)))
 MAKE_SYM_STORE_ARGS := -c --vcs-info
 DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
 MAKE_SYM_STORE_PATH := $(DIST)/bin
 endif
 MAKE_SYM_STORE_ARGS += --install-manifest=$(DEPTH)/_build_manifests/install/dist_include,$(DIST)/include
@@ -357,36 +327,16 @@ ifdef SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE
 	$(PYTHON) -u $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.py '$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
 endif
 endif
 
 .PHONY: update-packaging
 update-packaging:
 	$(MAKE) -C tools/update-packaging
 
-.PHONY: pretty-package
-pretty-package:
-	unset MOZ_SIGN_CMD && $(MAKE) package MOZ_PKG_PRETTYNAMES=1
-
-.PHONY: pretty-package-tests
-pretty-package-tests:
-	unset MOZ_SIGN_CMD && $(MAKE) package-tests MOZ_PKG_PRETTYNAMES=1
-
-.PHONY: pretty-l10n-check
-pretty-l10n-check:
-	unset MOZ_SIGN_CMD && $(MAKE) l10n-check MOZ_PKG_PRETTYNAMES=1
-
-.PHONY: pretty-update-packaging
-pretty-update-packaging:
-	unset MOZ_SIGN_CMD && $(MAKE) -C tools/update-packaging MOZ_PKG_PRETTYNAMES=1
-
-.PHONY: pretty-installer
-pretty-installer:
-	unset MOZ_SIGN_CMD && $(MAKE) installer MOZ_PKG_PRETTYNAMES=1
-
 #XXX: this is a hack, since we don't want to clobber for MSVC
 # PGO support, but we can't do this test in client.mk
 ifneq ($(OS_ARCH)_$(GNU_CC), WINNT_)
 # No point in clobbering if PGO has been explicitly disabled.
 ifndef NO_PROFILE_GUIDED_OPTIMIZE
 maybe_clobber_profiledbuild: clean
 else
 maybe_clobber_profiledbuild:
--- a/README.txt
+++ b/README.txt
@@ -1,27 +1,27 @@
 An explanation of the Mozilla Source Code Directory Structure and links to
 project pages with documentation can be found at:
 
     https://developer.mozilla.org/en/Mozilla_Source_Code_Directory_Structure
 
 For information on how to build Mozilla from the source code, see:
 
-    http://developer.mozilla.org/en/docs/Build_Documentation
+    https://developer.mozilla.org/en/docs/Build_Documentation
 
 To have your bug fix / feature added to Mozilla, you should create a patch and
 submit it to Bugzilla (https://bugzilla.mozilla.org). Instructions are at:
 
-    http://developer.mozilla.org/en/docs/Creating_a_patch
-    http://developer.mozilla.org/en/docs/Getting_your_patch_in_the_tree
+    https://developer.mozilla.org/en/docs/Creating_a_patch
+    https://developer.mozilla.org/en/docs/Getting_your_patch_in_the_tree
 
 If you have a question about developing Mozilla, and can't find the solution
-on http://developer.mozilla.org, you can try asking your question in a
+on https://developer.mozilla.org, you can try asking your question in a
 mozilla.* Usenet group, or on IRC at irc.mozilla.org. [The Mozilla news groups
 are accessible on Google Groups, or news.mozilla.org with a NNTP reader.]
 
 You can download nightly development builds from the Mozilla FTP server.
 Keep in mind that nightly builds, which are used by Mozilla developers for
 testing, may be buggy. Firefox nightlies, for example, can be found at:
 
     https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/
             - or -
-    http://nightly.mozilla.org/
+    https://nightly.mozilla.org/
--- a/accessible/aom/AccessibleNode.cpp
+++ b/accessible/aom/AccessibleNode.cpp
@@ -149,25 +149,27 @@ AccessibleNode::Has(const Sequence<nsStr
 
 void
 AccessibleNode::Get(JSContext* aCX, const nsAString& aAttribute,
                     JS::MutableHandle<JS::Value> aValue,
                     ErrorResult& aRv)
 {
   if (!mIntl) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
   }
 
   nsCOMPtr<nsIPersistentProperties> attrs = mIntl->Attributes();
   nsAutoString value;
   attrs->GetStringProperty(NS_ConvertUTF16toUTF8(aAttribute), value);
 
   JS::Rooted<JS::Value> jsval(aCX);
   if (!ToJSValue(aCX, value, &jsval)) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
   }
 
   aValue.set(jsval);
 }
 
 nsINode*
 AccessibleNode::GetDOMNode()
 {
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -8,32 +8,32 @@
 
 #include "Accessible-inl.h"
 #include "ApplicationAccessibleWrap.h"
 #include "InterfaceInitFuncs.h"
 #include "nsAccUtils.h"
 #include "mozilla/a11y/PDocAccessible.h"
 #include "OuterDocAccessible.h"
 #include "ProxyAccessible.h"
+#include "DocAccessibleParent.h"
 #include "RootAccessible.h"
 #include "TableAccessible.h"
 #include "TableCellAccessible.h"
 #include "nsMai.h"
 #include "nsMaiHyperlink.h"
 #include "nsString.h"
 #include "nsStateMap.h"
 #include "mozilla/a11y/Platform.h"
 #include "Relation.h"
 #include "RootAccessible.h"
 #include "States.h"
 #include "nsISimpleEnumerator.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Sprintf.h"
-#include "nsXPCOMStrings.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIPersistentProperties2.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 MaiAtkObject::EAvailableAtkSignals MaiAtkObject::gAvailableAtkSignals =
   eUnknown;
@@ -608,18 +608,17 @@ getNameCB(AtkObject* aAtkObj)
 
   return aAtkObj->name;
 }
 
 static void
 MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName)
 {
   NS_ConvertUTF16toUTF8 newNameUTF8(aNewName);
-  if (aAtkObj->name &&
-      !strncmp(aAtkObj->name, newNameUTF8.get(), newNameUTF8.Length()))
+  if (aAtkObj->name && !strcmp(aAtkObj->name, newNameUTF8.get()))
     return;
 
   // Below we duplicate the functionality of atk_object_set_name(),
   // but without calling atk_object_get_name(). Instead of
   // atk_object_get_name() we directly access aAtkObj->name. This is because
   // atk_object_get_name() would call getNameCB() which would call
   // MaybeFireNameChange() (or atk_object_set_name() before this problem was
   // fixed) and we would get an infinite recursion.
--- a/accessible/atk/nsMaiInterfaceTable.cpp
+++ b/accessible/atk/nsMaiInterfaceTable.cpp
@@ -322,44 +322,47 @@ getSelectedRowsCB(AtkTable *aTable, gint
 }
 
 static gboolean
 isColumnSelectedCB(AtkTable *aTable, gint aColIdx)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
   if (accWrap) {
     return static_cast<gboolean>(accWrap->AsTable()->IsColSelected(aColIdx));
-  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+  }
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
     return static_cast<gboolean>(proxy->TableColumnSelected(aColIdx));
   }
 
   return FALSE;
 }
 
 static gboolean
 isRowSelectedCB(AtkTable *aTable, gint aRowIdx)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
   if (accWrap) {
     return static_cast<gboolean>(accWrap->AsTable()->IsRowSelected(aRowIdx));
-  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+  }
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
     return static_cast<gboolean>(proxy->TableRowSelected(aRowIdx));
   }
 
   return FALSE;
 }
 
 static gboolean
 isCellSelectedCB(AtkTable *aTable, gint aRowIdx, gint aColIdx)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
   if (accWrap) {
     return static_cast<gboolean>(accWrap->AsTable()->
       IsCellSelected(aRowIdx, aColIdx));
-  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+  }
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
     return static_cast<gboolean>(proxy->TableCellSelected(aRowIdx, aColIdx));
   }
 
   return FALSE;
 }
 }
 
 void
--- a/accessible/atk/nsMaiInterfaceText.cpp
+++ b/accessible/atk/nsMaiInterfaceText.cpp
@@ -495,17 +495,18 @@ getTextSelectionCB(AtkText *aText, gint 
       return nullptr;
     }
 
     text->SelectionBoundsAt(aSelectionNum, &startOffset, &endOffset);
     *aStartOffset = startOffset;
     *aEndOffset = endOffset;
 
     return getTextCB(aText, *aStartOffset, *aEndOffset);
-  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+  }
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
     nsString data;
     proxy->SelectionBoundsAt(aSelectionNum, data, &startOffset, &endOffset);
     *aStartOffset = startOffset;
     *aEndOffset = endOffset;
 
     NS_ConvertUTF16toUTF8 dataAsUTF8(data);
     return (dataAsUTF8.get()) ? g_strdup(dataAsUTF8.get()) : nullptr;
   }
@@ -521,17 +522,18 @@ addTextSelectionCB(AtkText *aText,
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (accWrap) {
     HyperTextAccessible* text = accWrap->AsHyperText();
     if (!text || !text->IsTextRole()) {
       return FALSE;
     }
 
     return text->AddToSelection(aStartOffset, aEndOffset);
-  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+  }
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
     return proxy->AddToSelection(aStartOffset, aEndOffset);
   }
 
   return FALSE;
 }
 
 static gboolean
 removeTextSelectionCB(AtkText *aText,
@@ -540,17 +542,18 @@ removeTextSelectionCB(AtkText *aText,
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (accWrap) {
     HyperTextAccessible* text = accWrap->AsHyperText();
     if (!text || !text->IsTextRole()) {
       return FALSE;
     }
 
     return text->RemoveFromSelection(aSelectionNum);
-  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+  }
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
     return proxy->RemoveFromSelection(aSelectionNum);
   }
 
   return FALSE;
 }
 
 static gboolean
 setTextSelectionCB(AtkText *aText, gint aSelectionNum,
@@ -559,17 +562,18 @@ setTextSelectionCB(AtkText *aText, gint 
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (accWrap) {
     HyperTextAccessible* text = accWrap->AsHyperText();
     if (!text || !text->IsTextRole()) {
       return FALSE;
     }
 
     return text->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
-  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+  }
+  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
     return proxy->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
   }
 
   return FALSE;
 }
 
 static gboolean
 setCaretOffsetCB(AtkText *aText, gint aOffset)
--- a/accessible/base/ARIAMap.cpp
+++ b/accessible/base/ARIAMap.cpp
@@ -179,17 +179,17 @@ static const nsRoleMapEntry sWAIRoleMaps
   { // directory
     &nsGkAtoms::directory,
     roles::LIST,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
     eList,
-    kNoReqStates
+    states::READONLY
   },
   { // document
     &nsGkAtoms::document,
     roles::DOCUMENT,
     kUseMapRole,
     eNoValue,
     eNoAction,
     eNoLiveAttr,
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -516,44 +516,16 @@ DocManager::CreateDocOrRootAccessible(ns
     // the tree. The reorder event is delivered after the document tree is
     // constructed because event processing and tree construction are done by
     // the same document.
     // Note: don't use AccReorderEvent to avoid coalsecense and special reorder
     // events processing.
     docAcc->FireDelayedEvent(nsIAccessibleEvent::EVENT_REORDER,
                              ApplicationAcc());
 
-    if (IPCAccessibilityActive()) {
-      nsIDocShell* docShell = aDocument->GetDocShell();
-      if (docShell) {
-        nsCOMPtr<nsITabChild> tabChild = docShell->GetTabChild();
-
-        // XXX We may need to handle the case that we don't have a tab child
-        // differently.  It may be that this will cause us to fail to notify
-        // the parent process about important accessible documents.
-        if (tabChild) {
-          DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
-          docAcc->SetIPCDoc(ipcDoc);
-
-#if defined(XP_WIN)
-          IAccessibleHolder holder(CreateHolderFromAccessible(docAcc));
-#endif
-
-          static_cast<TabChild*>(tabChild.get())->
-            SendPDocAccessibleConstructor(ipcDoc, nullptr, 0,
-#if defined(XP_WIN)
-                                          AccessibleWrap::GetChildIDFor(docAcc),
-                                          holder
-#else
-                                          0, 0
-#endif
-                                          );
-        }
-      }
-    }
   } else {
     parentDocAcc->BindChildDocument(docAcc);
   }
 
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eDocCreate)) {
     logging::DocCreate("document creation finished", aDocument);
     logging::Stack();
--- a/accessible/base/NotificationController.cpp
+++ b/accessible/base/NotificationController.cpp
@@ -212,49 +212,49 @@ NotificationController::QueueMutationEve
   while (prevEvent && prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_REORDER) {
     prevEvent = prevEvent->PrevEvent();
   }
 
   if (prevEvent && prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_HIDE &&
       mutEvent->IsHide()) {
     AccHideEvent* prevHide = downcast_accEvent(prevEvent);
     AccTextChangeEvent* prevTextChange = prevHide->mTextChangeEvent;
-    if (prevTextChange) {
+    if (prevTextChange && prevHide->Parent() == mutEvent->Parent()) {
       if (prevHide->mNextSibling == target) {
         target->AppendTextTo(prevTextChange->mModifiedText);
+        prevHide->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
       } else if (prevHide->mPrevSibling == target) {
         nsString temp;
         target->AppendTextTo(temp);
 
         uint32_t extraLen = temp.Length();
         temp += prevTextChange->mModifiedText;;
         prevTextChange->mModifiedText = temp;
         prevTextChange->mStart -= extraLen;
+        prevHide->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
       }
-
-      prevHide->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
     }
   } else if (prevEvent && mutEvent->IsShow() &&
              prevEvent->GetEventType() == nsIAccessibleEvent::EVENT_SHOW) {
     AccShowEvent* prevShow = downcast_accEvent(prevEvent);
     AccTextChangeEvent* prevTextChange = prevShow->mTextChangeEvent;
-    if (prevTextChange) {
+    if (prevTextChange && prevShow->Parent() == target->Parent()) {
       int32_t index = target->IndexInParent();
       int32_t prevIndex = prevShow->GetAccessible()->IndexInParent();
       if (prevIndex + 1 == index) {
         target->AppendTextTo(prevTextChange->mModifiedText);
+        prevShow->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
       } else if (index + 1 == prevIndex) {
         nsString temp;
         target->AppendTextTo(temp);
         prevTextChange->mStart -= temp.Length();
         temp += prevTextChange->mModifiedText;
         prevTextChange->mModifiedText = temp;
+        prevShow->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
       }
-
-      prevShow->mTextChangeEvent.swap(mutEvent->mTextChangeEvent);
     }
   }
 
   if (!mutEvent->mTextChangeEvent) {
     mutEvent->mTextChangeEvent =
       new AccTextChangeEvent(container, offset, text, mutEvent->IsShow(),
                              aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
   }
@@ -324,30 +324,37 @@ NotificationController::CoalesceMutation
           AccReorderEvent* reorder = downcast_accEvent(mMutationMap.GetEvent(parent, EventMap::ReorderEvent));
 
           // We want to make sure that a reorder event comes after any show or
           // hide events targeted at the children of its target.  We keep the
           // invariant that event generation goes up as you are farther in the
           // queue, so we want to use the spot of the event with the higher
           // generation number, and keep that generation number.
           if (reorder && reorder->EventGeneration() < event->EventGeneration()) {
-            // There really should be a show or hide event before the first
-            // reorder event.
-            if (reorder->PrevEvent()) {
-              reorder->PrevEvent()->SetNextEvent(reorder->NextEvent());
-            } else {
-              mFirstMutationEvent = reorder->NextEvent();
+            reorder->SetEventGeneration(event->EventGeneration());
+
+            // It may be true that reorder was before event, and we coalesced
+            // away all the show / hide events between them.  In that case
+            // event is already immediately after reorder in the queue and we
+            // do not need to rearrange the list of events.
+            if (event != reorder->NextEvent()) {
+              // There really should be a show or hide event before the first
+              // reorder event.
+              if (reorder->PrevEvent()) {
+                reorder->PrevEvent()->SetNextEvent(reorder->NextEvent());
+              } else {
+                mFirstMutationEvent = reorder->NextEvent();
+              }
+
+              reorder->NextEvent()->SetPrevEvent(reorder->PrevEvent());
+              event->PrevEvent()->SetNextEvent(reorder);
+              reorder->SetPrevEvent(event->PrevEvent());
+              event->SetPrevEvent(reorder);
+              reorder->SetNextEvent(event);
             }
-
-            reorder->NextEvent()->SetPrevEvent(reorder->PrevEvent());
-            event->PrevEvent()->SetNextEvent(reorder);
-            reorder->SetPrevEvent(event->PrevEvent());
-            event->SetPrevEvent(reorder);
-            reorder->SetNextEvent(event);
-            reorder->SetEventGeneration(event->EventGeneration());
           }
           DropMutationEvent(event);
           break;
         }
 
         acc = parent;
       }
     } else if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
@@ -743,18 +750,21 @@ NotificationController::WillRefresh(mozi
 
         outerDocAcc->RemoveChild(childDoc);
       }
 
       // Failed to bind the child document, destroy it.
       childDoc->Shutdown();
     }
   }
-
   mHangingChildDocuments.Clear();
+  MOZ_ASSERT(mDocument, "Illicit document shutdown");
+  if (!mDocument) {
+    return;
+  }
 
   // If the document is ready and all its subdocuments are completely loaded
   // then process the document load.
   if (mDocument->HasLoadState(DocAccessible::eReady) &&
       !mDocument->HasLoadState(DocAccessible::eCompletelyLoaded) &&
       hangingDocCnt == 0) {
     uint32_t childDocCnt = mDocument->ChildDocumentCount(), childDocIdx = 0;
     for (; childDocIdx < childDocCnt; childDocIdx++) {
--- a/accessible/base/SelectionManager.h
+++ b/accessible/base/SelectionManager.h
@@ -116,17 +116,17 @@ protected:
 
   /**
    * Process DOM selection change. Fire selection and caret move events.
    */
   void ProcessSelectionChanged(SelData* aSelData);
 
 private:
   // Currently focused control.
-  nsWeakFrame mCurrCtrlFrame;
+  WeakFrame mCurrCtrlFrame;
   int32_t mCaretOffset;
   HyperTextAccessible* mAccWithCaret;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/base/TextAttrs.cpp
+++ b/accessible/base/TextAttrs.cpp
@@ -13,20 +13,16 @@
 #include "gfxFont.h"
 #include "nsFontMetrics.h"
 #include "nsLayoutUtils.h"
 #include "nsContainerFrame.h"
 #include "HyperTextAccessible.h"
 #include "mozilla/AppUnits.h"
 #include "mozilla/gfx/2D.h"
 
-#if defined(MOZ_WIDGET_GTK)
-#include "gfxPlatformGtk.h" // xxx - for UseFcFontList
-#endif
-
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // TextAttrsMgr
 ////////////////////////////////////////////////////////////////////////////////
 
 void
@@ -647,38 +643,24 @@ TextAttrsMgr::FontWeightTextAttr::
   // When there doesn't exist a bold font in the family and so the rendering of
   // a non-bold font face is changed so that the user sees what looks like a
   // bold font, i.e. synthetic bolding is used. IsSyntheticBold method is only
   // needed on Mac, but it is "safe" to use on all platforms.  (For non-Mac
   // platforms it always return false.)
   if (font->IsSyntheticBold())
     return 700;
 
-  bool useFontEntryWeight = true;
-
-  // Under Linux, when gfxPangoFontGroup code is used,
-  // font->GetStyle()->weight will give the absolute weight requested of the
-  // font face. The gfxPangoFontGroup code uses the gfxFontEntry constructor
-  // which doesn't initialize the weight field.
-#if defined(MOZ_WIDGET_GTK)
-  useFontEntryWeight = gfxPlatformGtk::UseFcFontList();
-#endif
-
-  if (useFontEntryWeight) {
-    // On Windows, font->GetStyle()->weight will give the same weight as
-    // fontEntry->Weight(), the weight of the first font in the font group,
-    // which may not be the weight of the font face used to render the
-    // characters. On Mac, font->GetStyle()->weight will just give the same
-    // number as getComputedStyle(). fontEntry->Weight() will give the weight
-    // of the font face used.
-    gfxFontEntry *fontEntry = font->GetFontEntry();
-    return fontEntry->Weight();
-  } else {
-    return font->GetStyle()->weight;
-  }
+  // On Windows, font->GetStyle()->weight will give the same weight as
+  // fontEntry->Weight(), the weight of the first font in the font group,
+  // which may not be the weight of the font face used to render the
+  // characters. On Mac, font->GetStyle()->weight will just give the same
+  // number as getComputedStyle(). fontEntry->Weight() will give the weight
+  // of the font face used.
+  gfxFontEntry *fontEntry = font->GetFontEntry();
+  return fontEntry->Weight();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // AutoGeneratedTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 TextAttrsMgr::AutoGeneratedTextAttr::
   AutoGeneratedTextAttr(HyperTextAccessible* aHyperTextAcc,
                         Accessible* aAccessible) :
--- a/accessible/base/moz.build
+++ b/accessible/base/moz.build
@@ -58,16 +58,18 @@ if CONFIG['A11Y_LOG']:
     UNIFIED_SOURCES += [
         'Logging.cpp',
     ]
 
 LOCAL_INCLUDES += [
     '/accessible/generic',
     '/accessible/html',
     '/accessible/ipc',
+    '/dom/base',
+    '/dom/xul',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     LOCAL_INCLUDES += [
         '/accessible/ipc/win',
     ]
 else:
     LOCAL_INCLUDES += [
--- a/accessible/base/nsAccCache.h
+++ b/accessible/base/nsAccCache.h
@@ -20,26 +20,9 @@ UnbindCacheEntriesFromDocument(
   for (auto iter = aCache.Iter(); !iter.Done(); iter.Next()) {
     T* accessible = iter.Data();
     MOZ_ASSERT(accessible && !accessible->IsDefunct());
     accessible->Document()->UnbindFromDocument(accessible);
     iter.Remove();
   }
 }
 
-/**
- * Clear the cache and shutdown the accessibles.
- */
-template <class T>
-static void
-ClearCache(nsRefPtrHashtable<nsPtrHashKey<const void>, T>& aCache)
-{
-  for (auto iter = aCache.Iter(); !iter.Done(); iter.Next()) {
-    T* accessible = iter.Data();
-    MOZ_ASSERT(accessible);
-    if (accessible && !accessible->IsDefunct()) {
-      accessible->Shutdown();
-    }
-    iter.Remove();
-  }
-}
-
 #endif
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -312,26 +312,23 @@ nsAccessibilityService::ListenersChanged
           listenerName != nsGkAtoms::onmousedown &&
           listenerName != nsGkAtoms::onmouseup) {
         continue;
       }
 
       nsIDocument* ownerDoc = node->OwnerDoc();
       DocAccessible* document = GetExistingDocAccessible(ownerDoc);
 
-      // Always recreate for onclick changes.
-      if (document) {
-        if (nsCoreUtils::HasClickListener(node)) {
-          if (!document->GetAccessible(node)) {
-            document->RecreateAccessible(node);
-          }
-        } else {
-          if (document->GetAccessible(node)) {
-            document->RecreateAccessible(node);
-          }
+      // Create an accessible for a inaccessible element having click event
+      // handler.
+      if (document && !document->HasAccessible(node) &&
+          nsCoreUtils::HasClickListener(node)) {
+        nsIContent* parentEl = node->GetFlattenedTreeParent();
+        if (parentEl) {
+          document->ContentInserted(parentEl, node, node->GetNextSibling());
         }
         break;
       }
     }
   }
   return NS_OK;
 }
 
@@ -593,16 +590,17 @@ nsAccessibilityService::ContentRemoved(n
     if (!child) {
       Accessible* container = document->GetContainerAccessible(aChildNode);
       a11y::TreeWalker walker(container ? container : document, aChildNode,
                               a11y::TreeWalker::eWalkCache);
       child = walker.Next();
     }
 
     if (child) {
+      MOZ_DIAGNOSTIC_ASSERT(child->Parent(), "Unattached accessible from tree");
       document->ContentRemoved(child->Parent(), aChildNode);
 #ifdef A11Y_LOG
       if (logging::IsEnabled(logging::eTree))
         logging::AccessibleNNode("real container", child->Parent());
 #endif
     }
   }
 
--- a/accessible/base/nsAccessibilityService.h
+++ b/accessible/base/nsAccessibilityService.h
@@ -338,22 +338,17 @@ nsAccessibilityService* GetOrCreateAccSe
 void MaybeShutdownAccService(uint32_t aFormerConsumer);
 
 /**
  * Return true if we're in a content process and not B2G.
  */
 inline bool
 IPCAccessibilityActive()
 {
-#ifdef MOZ_B2G
-  return false;
-#else
-  return XRE_IsContentProcess() &&
-    mozilla::Preferences::GetBool("accessibility.ipc_architecture.enabled", true);
-#endif
+  return XRE_IsContentProcess();
 }
 
 /**
  * Map nsIAccessibleEvents constants to strings. Used by
  * nsAccessibilityService::GetStringEventType() method.
  */
 static const char kEventTypeNames[][40] = {
   "unknown",                                 //
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -9,26 +9,28 @@
 
 #include "nsIBaseWindow.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocument.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsRange.h"
 #include "nsIBoxObject.h"
-#include "nsIDOMXULElement.h"
+#include "nsXULElement.h"
+#include "mozilla/dom/BoxObject.h"
 #include "nsIDocShell.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIScrollableFrame.h"
 #include "nsISelectionPrivate.h"
 #include "nsISelectionController.h"
 #include "nsISimpleEnumerator.h"
 #include "mozilla/dom/TouchEvent.h"
+#include "mozilla/ErrorResult.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TouchEvents.h"
 #include "nsView.h"
 #include "nsGkAtoms.h"
 
 #include "nsComponentManagerUtils.h"
@@ -92,28 +94,29 @@ nsCoreUtils::DispatchClickEvent(nsITreeB
   // Calculate x and y coordinates.
   int32_t x = 0, y = 0, width = 0, height = 0;
   nsresult rv = aTreeBoxObj->GetCoordsForCellItem(aRowIndex, aColumn,
                                                   aPseudoElt,
                                                   &x, &y, &width, &height);
   if (NS_FAILED(rv))
     return;
 
-  nsCOMPtr<nsIDOMXULElement> tcXULElm(do_QueryInterface(tcElm));
-  nsCOMPtr<nsIBoxObject> tcBoxObj;
-  tcXULElm->GetBoxObject(getter_AddRefs(tcBoxObj));
+  nsCOMPtr<nsIContent> tcXULElm(do_QueryInterface(tcElm));
+  IgnoredErrorResult ignored;
+  nsCOMPtr<nsIBoxObject> tcBoxObj =
+    nsXULElement::FromContent(tcXULElm)->GetBoxObject(ignored);
 
   int32_t tcX = 0;
   tcBoxObj->GetX(&tcX);
 
   int32_t tcY = 0;
   tcBoxObj->GetY(&tcY);
 
   // Dispatch mouse events.
-  nsWeakFrame tcFrame = tcContent->GetPrimaryFrame();
+  AutoWeakFrame tcFrame = tcContent->GetPrimaryFrame();
   nsIFrame* rootFrame = presShell->GetRootFrame();
 
   nsPoint offset;
   nsIWidget *rootWidget =
     rootFrame->GetView()->GetNearestWidget(&offset);
 
   RefPtr<nsPresContext> presContext = presShell->GetPresContext();
 
@@ -484,42 +487,41 @@ nsCoreUtils::GetLanguageFor(nsIContent *
     walkUp = walkUp->GetParent();
 }
 
 already_AddRefed<nsIBoxObject>
 nsCoreUtils::GetTreeBodyBoxObject(nsITreeBoxObject *aTreeBoxObj)
 {
   nsCOMPtr<nsIDOMElement> tcElm;
   aTreeBoxObj->GetTreeBody(getter_AddRefs(tcElm));
-  nsCOMPtr<nsIDOMXULElement> tcXULElm(do_QueryInterface(tcElm));
+  nsCOMPtr<nsIContent> tcContent(do_QueryInterface(tcElm));
+  RefPtr<nsXULElement> tcXULElm = nsXULElement::FromContentOrNull(tcContent);
   if (!tcXULElm)
     return nullptr;
 
-  nsCOMPtr<nsIBoxObject> boxObj;
-  tcXULElm->GetBoxObject(getter_AddRefs(boxObj));
-  return boxObj.forget();
+  IgnoredErrorResult ignored;
+  return tcXULElm->GetBoxObject(ignored);
 }
 
 already_AddRefed<nsITreeBoxObject>
 nsCoreUtils::GetTreeBoxObject(nsIContent *aContent)
 {
   // Find DOMNode's parents recursively until reach the <tree> tag
   nsIContent* currentContent = aContent;
   while (currentContent) {
     if (currentContent->NodeInfo()->Equals(nsGkAtoms::tree,
                                            kNameSpaceID_XUL)) {
       // We will get the nsITreeBoxObject from the tree node
-      nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(currentContent));
-      if (xulElement) {
-        nsCOMPtr<nsIBoxObject> box;
-        xulElement->GetBoxObject(getter_AddRefs(box));
-        nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(box));
-        if (treeBox)
-          return treeBox.forget();
-      }
+      RefPtr<nsXULElement> xulElement =
+        nsXULElement::FromContent(currentContent);
+      IgnoredErrorResult ignored;
+      nsCOMPtr<nsIBoxObject> box = xulElement->GetBoxObject(ignored);
+      nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(box));
+      if (treeBox)
+        return treeBox.forget();
     }
     currentContent = currentContent->GetFlattenedTreeParent();
   }
 
   return nullptr;
 }
 
 already_AddRefed<nsITreeColumn>
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -88,17 +88,23 @@
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible: nsISupports and cycle collection
 
-NS_IMPL_CYCLE_COLLECTION(Accessible, mContent)
+NS_IMPL_CYCLE_COLLECTION_CLASS(Accessible)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Accessible)
+  tmp->Shutdown();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Accessible)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent, mDoc)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Accessible)
   if (aIID.Equals(NS_GET_IID(Accessible)))
     foundInterface = this;
   else
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, Accessible)
 NS_INTERFACE_MAP_END
 
@@ -1819,17 +1825,17 @@ Accessible::DispatchClickEvent(nsIConten
   nsCOMPtr<nsIPresShell> presShell = mDoc->PresShell();
 
   // Scroll into view.
   presShell->ScrollContentIntoView(aContent,
                                    nsIPresShell::ScrollAxis(),
                                    nsIPresShell::ScrollAxis(),
                                    nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
 
-  nsWeakFrame frame = aContent->GetPrimaryFrame();
+  AutoWeakFrame frame = aContent->GetPrimaryFrame();
   if (!frame)
     return;
 
   // Compute x and y coordinates.
   nsPoint point;
   nsCOMPtr<nsIWidget> widget = frame->GetNearestWidget(point);
   if (!widget)
     return;
@@ -2120,48 +2126,53 @@ Accessible::InsertChildAt(uint32_t aInde
 
   aChild->BindToParent(this, aIndex);
   return true;
 }
 
 bool
 Accessible::RemoveChild(Accessible* aChild)
 {
-  if (!aChild)
-    return false;
-
-  if (aChild->mParent != this || aChild->mIndexInParent == -1)
-    return false;
-
-  MOZ_ASSERT((mStateFlags & eKidsMutating) || aChild->IsDefunct() || aChild->IsDoc(),
-             "Illicit children change");
+  MOZ_DIAGNOSTIC_ASSERT(aChild, "No child was given");
+  MOZ_DIAGNOSTIC_ASSERT(aChild->mParent, "No parent");
+  MOZ_DIAGNOSTIC_ASSERT(aChild->mParent == this, "Wrong parent");
+  MOZ_DIAGNOSTIC_ASSERT(aChild->mIndexInParent != -1, "Unbound child was given");
+  MOZ_DIAGNOSTIC_ASSERT((mStateFlags & eKidsMutating) || aChild->IsDefunct() || aChild->IsDoc(),
+                        "Illicit children change");
 
   int32_t index = static_cast<uint32_t>(aChild->mIndexInParent);
-  MOZ_ASSERT(mChildren.SafeElementAt(index) == aChild,
-             "A wrong child index");
+  if (mChildren.SafeElementAt(index) != aChild) {
+    MOZ_ASSERT_UNREACHABLE("A wrong child index");
+    index = mChildren.IndexOf(aChild);
+    if (index == -1) {
+      MOZ_ASSERT_UNREACHABLE("No child was found");
+      return false;
+    }
+  }
 
   aChild->UnbindFromParent();
   mChildren.RemoveElementAt(index);
 
   for (uint32_t idx = index; idx < mChildren.Length(); idx++) {
     mChildren[idx]->mIndexInParent = idx;
   }
 
   return true;
 }
 
 void
 Accessible::MoveChild(uint32_t aNewIndex, Accessible* aChild)
 {
-  MOZ_ASSERT(aChild, "No child was given");
-  MOZ_ASSERT(aChild->mParent == this, "A child from different subtree was given");
-  MOZ_ASSERT(aChild->mIndexInParent != -1, "Unbound child was given");
-  MOZ_ASSERT(static_cast<uint32_t>(aChild->mIndexInParent) != aNewIndex,
+  MOZ_DIAGNOSTIC_ASSERT(aChild, "No child was given");
+  MOZ_DIAGNOSTIC_ASSERT(aChild->mParent == this, "A child from different subtree was given");
+  MOZ_DIAGNOSTIC_ASSERT(aChild->mIndexInParent != -1, "Unbound child was given");
+  MOZ_DIAGNOSTIC_ASSERT(aChild->mParent->GetChildAt(aChild->mIndexInParent) == aChild, "Wrong index in parent");
+  MOZ_DIAGNOSTIC_ASSERT(static_cast<uint32_t>(aChild->mIndexInParent) != aNewIndex,
              "No move, same index");
-  MOZ_ASSERT(aNewIndex <= mChildren.Length(), "Wrong new index was given");
+  MOZ_DIAGNOSTIC_ASSERT(aNewIndex <= mChildren.Length(), "Wrong new index was given");
 
   RefPtr<AccHideEvent> hideEvent = new AccHideEvent(aChild, false);
   if (mDoc->Controller()->QueueMutationEvent(hideEvent)) {
     aChild->SetHideEventTarget(true);
   }
 
   mEmbeddedObjCollector = nullptr;
   mChildren.RemoveElementAt(aChild->mIndexInParent);
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -1133,17 +1133,17 @@ protected:
 
   /**
    * Return group info.
    */
   AccGroupInfo* GetGroupInfo();
 
   // Data Members
   nsCOMPtr<nsIContent> mContent;
-  DocAccessible* mDoc;
+  RefPtr<DocAccessible> mDoc;
 
   Accessible* mParent;
   nsTArray<Accessible*> mChildren;
   int32_t mIndexInParent;
 
   static const uint8_t kStateFlagsBits = 13;
   static const uint8_t kContextFlagsBits = 3;
   static const uint8_t kTypeBits = 6;
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -41,16 +41,17 @@
 #include "nsIScrollableFrame.h"
 #include "nsUnicharUtils.h"
 #include "nsIURI.h"
 #include "nsIWebNavigation.h"
 #include "nsFocusManager.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/EventStates.h"
+#include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/DocumentType.h"
 #include "mozilla/dom/Element.h"
 
 #ifdef MOZ_XUL
 #include "nsIXULDocument.h"
 #endif
 
 using namespace mozilla;
@@ -74,28 +75,34 @@ static nsIAtom** kRelationAttrs[] =
 
 static const uint32_t kRelationAttrsLen = ArrayLength(kRelationAttrs);
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor/desctructor
 
 DocAccessible::
   DocAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell) :
-  HyperTextAccessibleWrap(nullptr, this),
+    // XXX don't pass a document to the Accessible constructor so that we don't
+    // set mDoc until our vtable is fully setup.  If we set mDoc before setting
+    // up the vtable we will call Accessible::AddRef() but not the overrides of
+    // it for subclasses.  It is important to call those overrides to avoid
+    // confusing leak checking machinary.
+  HyperTextAccessibleWrap(nullptr, nullptr),
   // XXX aaronl should we use an algorithm for the initial cache size?
   mAccessibleCache(kDefaultCacheLength),
   mNodeToAccessibleMap(kDefaultCacheLength),
   mDocumentNode(aDocument),
   mScrollPositionChangedTicks(0),
   mLoadState(eTreeConstructionPending), mDocFlags(0), mLoadEventType(0),
   mVirtualCursor(nullptr),
   mPresShell(aPresShell), mIPCDoc(nullptr)
 {
   mGenericTypes |= eDocument;
   mStateFlags |= eNotNodeMapEntry;
+  mDoc = this;
 
   MOZ_ASSERT(mPresShell, "should have been given a pres shell");
   mPresShell->SetDocAccessible(this);
 
   // If this is a XUL Document, it should not implement nsHyperText
   if (mDocumentNode && mDocumentNode->IsXULDocument())
     mGenericTypes &= ~eHyperText;
 }
@@ -471,17 +478,27 @@ DocAccessible::Shutdown()
     mVirtualCursor = nullptr;
   }
 
   mPresShell->SetDocAccessible(nullptr);
   mPresShell = nullptr;  // Avoid reentrancy
 
   mDependentIDsHash.Clear();
   mNodeToAccessibleMap.Clear();
-  ClearCache(mAccessibleCache);
+
+  for (auto iter = mAccessibleCache.Iter(); !iter.Done(); iter.Next()) {
+    Accessible* accessible = iter.Data();
+    MOZ_ASSERT(accessible);
+    if (accessible && !accessible->IsDefunct()) {
+      // Unlink parent to avoid its cleaning overhead in shutdown.
+      accessible->mParent = nullptr;
+      accessible->Shutdown();
+    }
+    iter.Remove();
+  }
 
   HyperTextAccessibleWrap::Shutdown();
 
   GetAccService()->NotifyOfDocumentShutdown(this, kungFuDeathGripDoc);
 }
 
 nsIFrame*
 DocAccessible::GetFrame() const
@@ -1455,18 +1472,35 @@ DocAccessible::NotifyOfLoading(bool aIsR
   RefPtr<AccEvent> stateEvent =
     new AccStateChangeEvent(this, states::BUSY, true);
   FireDelayedEvent(stateEvent);
 }
 
 void
 DocAccessible::DoInitialUpdate()
 {
-  if (nsCoreUtils::IsTabDocument(mDocumentNode))
+  if (nsCoreUtils::IsTabDocument(mDocumentNode)) {
     mDocFlags |= eTabDocument;
+    if (IPCAccessibilityActive()) {
+      nsIDocShell* docShell = mDocumentNode->GetDocShell();
+      if (RefPtr<dom::TabChild> tabChild = dom::TabChild::GetFrom(docShell)) {
+        DocAccessibleChild* ipcDoc = new DocAccessibleChild(this);
+        SetIPCDoc(ipcDoc);
+
+#if defined(XP_WIN)
+        IAccessibleHolder holder(CreateHolderFromAccessible(this));
+        int32_t childID = AccessibleWrap::GetChildIDFor(this);
+#else
+        int32_t holder = 0, childID = 0;
+#endif
+        tabChild->SendPDocAccessibleConstructor(ipcDoc, nullptr, 0, childID,
+                                                holder);
+      }
+    }
+  }
 
   mLoadState |= eTreeConstructed;
 
   // Set up a root element and ARIA role mapping.
   UpdateRootElIfNeeded();
 
   // Build initial tree.
   CacheChildrenInSubtree(this);
@@ -2058,21 +2092,23 @@ DocAccessible::DoARIAOwnsRelocation(Acce
           TreeMutation imut(aOwner);
           aOwner->InsertChildAt(insertIdx, child);
           imut.AfterInsertion(child);
           imut.Done();
 
           child->SetRelocated(true);
           children->InsertElementAt(arrayIdx, child);
 
+          // Create subtree before adjusting the insertion index, since subtree
+          // creation may alter children in the container.
+          CreateSubtree(child);
+          FireEventsOnInsertion(aOwner);
+
           insertIdx = child->IndexInParent() + 1;
           arrayIdx++;
-
-          CreateSubtree(child);
-          FireEventsOnInsertion(aOwner);
         }
       }
       continue;
     }
 
 #ifdef A11Y_LOG
   logging::TreeInfo("aria owns traversal", logging::eVerbose,
                     "candidate", child, nullptr);
--- a/accessible/generic/DocAccessible.h
+++ b/accessible/generic/DocAccessible.h
@@ -347,17 +347,17 @@ public:
   void ContentRemoved(Accessible* aContainer, nsIContent* aChildNode)
   {
     // Update the whole tree of this document accessible when the container is
     // null (document element is removed).
     UpdateTreeOnRemoval((aContainer ? aContainer : this), aChildNode);
   }
   void ContentRemoved(nsIContent* aContainerNode, nsIContent* aChildNode)
   {
-    ContentRemoved(GetAccessibleOrContainer(aContainerNode), aChildNode);
+    ContentRemoved(AccessibleOrTrueContainer(aContainerNode), aChildNode);
   }
 
   /**
    * Updates accessible tree when rendered text is changed.
    */
   void UpdateText(nsIContent* aTextNode);
 
   /**
--- a/accessible/generic/OuterDocAccessible.cpp
+++ b/accessible/generic/OuterDocAccessible.cpp
@@ -25,16 +25,22 @@ using namespace mozilla::a11y;
 ////////////////////////////////////////////////////////////////////////////////
 
 OuterDocAccessible::
   OuterDocAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   AccessibleWrap(aContent, aDoc)
 {
   mType = eOuterDocType;
 
+#ifdef XP_WIN
+  if (DocAccessibleParent* remoteDoc = RemoteChildDoc()) {
+    remoteDoc->SendParentCOMProxy();
+  }
+#endif
+
   // Request document accessible for the content document to make sure it's
   // created. It will appended to outerdoc accessible children asynchronously.
   nsIDocument* outerDoc = mContent->GetUncomposedDoc();
   if (outerDoc) {
     nsIDocument* innerDoc = outerDoc->GetSubDocumentFor(mContent);
     if (innerDoc)
       GetAccService()->GetDocAccessible(innerDoc);
   }
@@ -202,17 +208,17 @@ OuterDocAccessible::GetChildAt(uint32_t 
   if (!remoteChild) {
     return nullptr;
   }
   return WrapperFor(remoteChild);
 }
 
 #endif // defined(XP_WIN)
 
-ProxyAccessible*
+DocAccessibleParent*
 OuterDocAccessible::RemoteChildDoc() const
 {
   dom::TabParent* tab = dom::TabParent::GetFrom(GetContent());
   if (!tab)
     return nullptr;
 
   return tab->GetTopLevelDocAccessible();
 }
--- a/accessible/generic/OuterDocAccessible.h
+++ b/accessible/generic/OuterDocAccessible.h
@@ -5,17 +5,17 @@
 
 #ifndef MOZILLA_A11Y_OUTERDOCACCESSIBLE_H_
 #define MOZILLA_A11Y_OUTERDOCACCESSIBLE_H_
 
 #include "AccessibleWrap.h"
 
 namespace mozilla {
 namespace a11y {
-class ProxyAccessible;
+class DocAccessibleParent;
 
 /**
  * Used for <browser>, <frame>, <iframe>, <page> or editor> elements.
  * 
  * In these variable names, "outer" relates to the OuterDocAccessible as
  * opposed to the DocAccessibleWrap which is "inner". The outer node is
  * a something like tags listed above, whereas the inner node corresponds to
  * the inner document root.
@@ -23,17 +23,17 @@ class ProxyAccessible;
 
 class OuterDocAccessible final : public AccessibleWrap
 {
 public:
   OuterDocAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   NS_DECL_ISUPPORTS_INHERITED
 
-  ProxyAccessible* RemoteChildDoc() const;
+  DocAccessibleParent* RemoteChildDoc() const;
 
   // Accessible
   virtual void Shutdown() override;
   virtual mozilla::a11y::role NativeRole() override;
   virtual Accessible* ChildAtPoint(int32_t aX, int32_t aY,
                                    EWhichChildAtPoint aWhichChild) override;
 
   virtual bool InsertChildAt(uint32_t aIdx, Accessible* aChild) override;
--- a/accessible/interfaces/gecko/IGeckoCustom.idl
+++ b/accessible/interfaces/gecko/IGeckoCustom.idl
@@ -7,16 +7,19 @@
 import "objidl.idl";
 import "oaidl.idl";
 
 [object, uuid(7510360f-cdae-4de9-88c8-d167eda62afc)]
 interface IGeckoCustom : IUnknown
 {
   [propget] HRESULT ID([out, retval] unsigned __int64* aID);
   [propget] HRESULT anchorCount([out, retval] long* aCount);
+  [propget] HRESULT DOMNodeID([out, retval] BSTR* aID);
+  [propget] HRESULT minimumIncrement([out, retval] double* aIncrement);
+  [propget] HRESULT mozState([out, retval] unsigned __int64* aState);
 }
 
 
 [
     uuid(55769d85-f830-4d76-9e39-3670914a28f7),
     helpstring("private custom gecko interfaces")
 ]
 library IGeckoCustom
--- a/accessible/interfaces/gecko/Makefile.in
+++ b/accessible/interfaces/gecko/Makefile.in
@@ -1,19 +1,21 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-GARBAGE += $(MIDL_GENERATED_FILES) done_gen dlldata.c
+GARBAGE += $(MIDL_GENERATED_FILES) done_gen
 
 MIDL_GENERATED_FILES = \
-	IGeckoCustom.h \
-	IGeckoCustom_p.c \
-	IGeckoCustom_i.c \
-	$(NULL)
+  dlldata.c \
+  IGeckoCustom.h \
+  IGeckoCustom_p.c \
+  IGeckoCustom_i.c \
+  IGeckoCustom.tlb \
+  $(NULL)
 
 $(MIDL_GENERATED_FILES): done_gen
 
 done_gen: IGeckoCustom.idl
 	$(MIDL) $(MIDL_FLAGS) -I $(srcdir) -Oicf $(srcdir)/IGeckoCustom.idl
 	touch $@
 
 export:: done_gen
--- a/accessible/interfaces/gecko/moz.build
+++ b/accessible/interfaces/gecko/moz.build
@@ -6,17 +6,21 @@
 
 SOURCES += [
     '!dlldata.c',
     '!IGeckoCustom_i.c',
     '!IGeckoCustom_p.c',
 ]
 
 GENERATED_FILES += [
+    'dlldata.c',
+    'IGeckoCustom.h',
     'IGeckoCustom.tlb',
+    'IGeckoCustom_i.c',
+    'IGeckoCustom_p.c',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 # The Windows MIDL code generator creates things like:
 #
 #   #endif !_MIDL_USE_GUIDDEF_
 #
--- a/accessible/interfaces/ia2/Makefile.in
+++ b/accessible/interfaces/ia2/Makefile.in
@@ -1,16 +1,18 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 IA2DIR        = $(topsrcdir)/other-licenses/ia2
 
 GARBAGE       += $(MIDL_GENERATED_FILES) \
                  $(MIDL_UNUSED_GENERATED_FILES) \
+                 midl_done \
+                 typelib_done \
                  $(NULL)
 
 # Please keep this list in sync with the moz.build file until the rest of this
 # Makefile is ported over.
 MIDL_INTERFACES = \
   Accessible2.idl \
   Accessible2_2.idl \
   Accessible2_3.idl \
@@ -48,20 +50,21 @@ MIDL_LIBRARIES = \
 CSRCS = \
   dlldata.c \
   $(MIDL_INTERFACES:%.idl=%_p.c) \
   $(MIDL_INTERFACES:%.idl=%_i.c) \
   $(NULL)
 
 MIDL_GENERATED_FILES = \
   dlldata.c \
+  $(MIDL_ENUMS:%.idl=%.h) \
   $(MIDL_INTERFACES:%.idl=%_p.c) \
   $(MIDL_INTERFACES:%.idl=%_i.c) \
   $(MIDL_INTERFACES:%.idl=%.h) \
-  $(MIDL_ENUMS:%.idl=%.h) \
+  $(MIDL_LIBRARIES:%.idl=%.tlb) \
   $(NULL)
 
 # We want to generate a .tlb from MIDL_LIBRARIES, but midl also generates
 # a bunch of .h and .c files that we're not interested in.
 MIDL_UNUSED_GENERATED_FILES = \
   $(MIDL_LIBRARIES:%.idl=%_p.c) \
   $(MIDL_LIBRARIES:%.idl=%_i.c) \
   $(MIDL_LIBRARIES:%.idl=%.h) \
@@ -75,18 +78,18 @@ midl_FILES := $(filter %.h %_i.c,$(MIDL_
 midl_DEST = $(DIST)/include
 midl_TARGET := midl
 
 export:: midl
 
 include $(topsrcdir)/config/rules.mk
 
 # generate list of to-be-generated files that are missing
-# but ignore special file dlldata.c
-missing:=$(strip $(foreach onefile,$(strip $(subst dlldata.c,,$(MIDL_GENERATED_FILES))),$(if $(wildcard $(onefile)),,$(onefile))))
+# but ignore special file dlldata.c and .tlb files
+missing:=$(strip $(foreach onefile,$(strip $(patsubst %.tlb,,$(subst dlldata.c,,$(MIDL_GENERATED_FILES)))),$(if $(wildcard $(onefile)),,$(onefile))))
 
 missing_base:=$(sort $(basename $(subst _p.c,,$(subst _i.c,,$(missing)))))
 
 $(MIDL_GENERATED_FILES) : midl_done typelib_done
 
 ifneq ("$(missing)","")
 midl_done : FORCE
 endif
@@ -94,17 +97,17 @@ endif
 midl_done : $(addprefix $(IA2DIR)/,$(MIDL_INTERFACES) $(MIDL_ENUMS))
 	for idl in $(sort $(subst FORCE,,$?) $(addsuffix .idl,$(addprefix $(IA2DIR)/,$(missing_base)))); do \
 	  $(MIDL) $(MIDL_FLAGS) -app_config -I $(IA2DIR) -Oicf $$idl; \
 	done
 	touch $@
 
 # The intent of this rule is to generate the .tlb file that is referenced in the
 # .rc file for IA2Marshal.dll
-typelib_done : $(MIDL_LIBRARIES)
+typelib_done : $(addprefix $(srcdir)/,$(MIDL_LIBRARIES))
 	for idl in $?; do \
-		$(MIDL) $(MIDL_FLAGS) -app_config -I $(IA2DIR) -D _MIDL_DECLARE_WIREM_HANDLE -dlldata `basename $$idl .idl`.c -Oicf $$idl; \
+	  $(MIDL) $(MIDL_FLAGS) -app_config -I $(IA2DIR) -D _MIDL_DECLARE_WIREM_HANDLE -dlldata `basename $$idl .idl`.c -Oicf $$idl; \
 	done
 	touch $@
 
 # This marshall dll is NOT registered in the installer (agreed to by IA2 participants)
 register::
 	regsvr32 -s $(DIST)/bin/$(SHARED_LIBRARY)
--- a/accessible/interfaces/ia2/moz.build
+++ b/accessible/interfaces/ia2/moz.build
@@ -14,16 +14,78 @@ OS_LIBS += [
     'uuid',
     'kernel32',
     'rpcrt4',
     'ole32',
     'oleaut32',
 ]
 
 GENERATED_FILES += [
+    'Accessible2.h',
+    'Accessible2_2.h',
+    'Accessible2_2_i.c',
+    'Accessible2_2_p.c',
+    'Accessible2_3.h',
+    'Accessible2_3_i.c',
+    'Accessible2_3_p.c',
+    'Accessible2_i.c',
+    'Accessible2_p.c',
+    'AccessibleAction.h',
+    'AccessibleAction_i.c',
+    'AccessibleAction_p.c',
+    'AccessibleApplication.h',
+    'AccessibleApplication_i.c',
+    'AccessibleApplication_p.c',
+    'AccessibleComponent.h',
+    'AccessibleComponent_i.c',
+    'AccessibleComponent_p.c',
+    'AccessibleDocument.h',
+    'AccessibleDocument_i.c',
+    'AccessibleDocument_p.c',
+    'AccessibleEditableText.h',
+    'AccessibleEditableText_i.c',
+    'AccessibleEditableText_p.c',
+    'AccessibleEventId.h',
+    'AccessibleHyperlink.h',
+    'AccessibleHyperlink_i.c',
+    'AccessibleHyperlink_p.c',
+    'AccessibleHypertext.h',
+    'AccessibleHypertext2.h',
+    'AccessibleHypertext2_i.c',
+    'AccessibleHypertext2_p.c',
+    'AccessibleHypertext_i.c',
+    'AccessibleHypertext_p.c',
+    'AccessibleImage.h',
+    'AccessibleImage_i.c',
+    'AccessibleImage_p.c',
+    'AccessibleRelation.h',
+    'AccessibleRelation_i.c',
+    'AccessibleRelation_p.c',
+    'AccessibleRole.h',
+    'AccessibleStates.h',
+    'AccessibleTable.h',
+    'AccessibleTable2.h',
+    'AccessibleTable2_i.c',
+    'AccessibleTable2_p.c',
+    'AccessibleTable_i.c',
+    'AccessibleTable_p.c',
+    'AccessibleTableCell.h',
+    'AccessibleTableCell_i.c',
+    'AccessibleTableCell_p.c',
+    'AccessibleText.h',
+    'AccessibleText2.h',
+    'AccessibleText2_i.c',
+    'AccessibleText2_p.c',
+    'AccessibleText_i.c',
+    'AccessibleText_p.c',
+    'AccessibleValue.h',
+    'AccessibleValue_i.c',
+    'AccessibleValue_p.c',
+    'dlldata.c',
+    'IA2CommonTypes.h',
     'IA2Typelib.tlb',
 ]
 
 RCINCLUDE = 'IA2Marshal.rc'
 
 # The Windows MIDL code generator creates things like:
 #
 #   #endif !_MIDL_USE_GUIDDEF_
--- a/accessible/interfaces/msaa/AccessibleMarshal.rc
+++ b/accessible/interfaces/msaa/AccessibleMarshal.rc
@@ -1,5 +1,5 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-1 typelib ISimpleDOMNode.tlb
+1 typelib ISimpleDOM.tlb
new file mode 100644
--- /dev/null
+++ b/accessible/interfaces/msaa/ISimpleDOM.idl
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// We use #include instead of import here so that MIDL treats these files as
+// part of the current file, thus forcing MIDL to generate proxy info for them.
+#include "ISimpleDOMNode.idl"
+#include "ISimpleDOMDocument.idl"
+#include "ISimpleDOMText.idl"
+
+[
+  uuid(a6245497-9c0b-4449-85a5-bd6ad07df8ea),
+  helpstring("ISimpleDOM Type Library")
+]
+library ISimpleDOM
+{
+  interface ISimpleDOMNode;
+  interface ISimpleDOMText;
+  interface ISimpleDOMDocument;
+};
+
--- a/accessible/interfaces/msaa/ISimpleDOMNode.idl
+++ b/accessible/interfaces/msaa/ISimpleDOMNode.idl
@@ -94,19 +94,16 @@ cpp_quote("//")
 cpp_quote("//")
 cpp_quote("///////////////////////////////////////////////////////////////////////////////////////////////////////")
 cpp_quote("")
 cpp_quote("")
 
 import "objidl.idl";
 import "oaidl.idl";
 
-import "ISimpleDOMText.idl";
-import "ISimpleDOMDocument.idl";
-
 [object, uuid(1814ceeb-49e2-407f-af99-fa755a7d2607)]
 interface ISimpleDOMNode : IUnknown
 {
   const unsigned short NODETYPE_ELEMENT = 1;
   const unsigned short NODETYPE_ATTRIBUTE = 2;
   const unsigned short NODETYPE_TEXT = 3;
   const unsigned short NODETYPE_CDATA_SECTION = 4;
   const unsigned short NODETYPE_ENTITY_REFERENCE = 5;
@@ -169,20 +166,8 @@ interface ISimpleDOMNode : IUnknown
 
   [propget] HRESULT innerHTML([out, retval] BSTR *innerHTML);
 
   [propget, local] HRESULT localInterface([out][retval] void **localInterface);
 
   [propget] HRESULT language([out, retval] BSTR *language);
 }
 
-
-[
-    uuid(a6245497-9c0b-4449-85a5-bd6ad07df8ea), 
-    helpstring("ISimpleDOM Type Library")
-] 
-library ISimpleDOM 
-{
-  interface ISimpleDOMNode;
-  interface ISimpleDOMText;
-  interface ISimpleDOMDocument;
-};
-
--- a/accessible/interfaces/msaa/Makefile.in
+++ b/accessible/interfaces/msaa/Makefile.in
@@ -1,52 +1,43 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-GARBAGE += $(MIDL_GENERATED_FILES) done_gen dlldata.c
+GARBAGE += $(MIDL_GENERATED_FILES) done_gen
 
 MIDL_GENERATED_FILES = \
-	ISimpleDOMNode.h \
-	ISimpleDOMNode_p.c \
-	ISimpleDOMNode_i.c \
-	ISimpleDOMDocument.h \
-	ISimpleDOMDocument_p.c \
-	ISimpleDOMDocument_i.c \
-	ISimpleDOMText.h \
-	ISimpleDOMText_p.c \
-	ISimpleDOMText_i.c \
-	$(NULL)
+  dlldata.c \
+  ISimpleDOM.h \
+  ISimpleDOM_i.c \
+  ISimpleDOM_p.c \
+  ISimpleDOM.tlb \
+  $(NULL)
 
 $(MIDL_GENERATED_FILES): done_gen
 
-done_gen: ISimpleDOMNode.idl \
+done_gen: ISimpleDOM.idl \
+          ISimpleDOMNode.idl \
           ISimpleDOMDocument.idl \
           ISimpleDOMText.idl
 
-	$(MIDL) $(MIDL_FLAGS) -I $(srcdir) -Oicf $(srcdir)/ISimpleDOMNode.idl
-	$(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/ISimpleDOMDocument.idl
-	$(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/ISimpleDOMText.idl
+	$(MIDL) $(MIDL_FLAGS) -I $(srcdir) -robust -Oicf $(srcdir)/ISimpleDOM.idl
 	touch $@
 
 export:: done_gen
 
 # This marshall dll is also registered in the installer
 register::
 	regsvr32 -s $(DIST)/bin/$(SHARED_LIBRARY)
 
 EMBED_MANIFEST_AT = 2
 
 midl_exports := \
-    ISimpleDOMDocument.h \
-    ISimpleDOMDocument_i.c \
-    ISimpleDOMNode.h \
-    ISimpleDOMNode_i.c \
-    ISimpleDOMText.h \
-    ISimpleDOMText_i.c \
+    ISimpleDOM.h \
+    ISimpleDOM_i.c \
     $(NULL)
 
 INSTALL_TARGETS += midl_exports
 midl_exports_FILES := $(midl_exports)
 midl_exports_DEST = $(DIST)/include
 midl_exports_TARGET := midl
 
 export:: midl
--- a/accessible/interfaces/msaa/moz.build
+++ b/accessible/interfaces/msaa/moz.build
@@ -3,36 +3,39 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 GeckoSharedLibrary('AccessibleMarshal', linkage=None)
 
 SOURCES += [
     '!dlldata.c',
-    '!ISimpleDOMDocument_i.c',
-    '!ISimpleDOMDocument_p.c',
-    '!ISimpleDOMNode_i.c',
-    '!ISimpleDOMNode_p.c',
-    '!ISimpleDOMText_i.c',
-    '!ISimpleDOMText_p.c',
+    '!ISimpleDOM_i.c',
+    '!ISimpleDOM_p.c',
 ]
 
 DEFINES['REGISTER_PROXY_DLL'] = True
+# The following line is required to preserve compatibility with older versions
+# of AccessibleMarshal.dll.
+DEFINES['PROXY_CLSID'] = 'IID_ISimpleDOMNode'
 
 DEFFILE = SRCDIR + '/AccessibleMarshal.def'
 
 OS_LIBS += [
     'kernel32',
     'rpcrt4',
     'oleaut32',
 ]
 
 GENERATED_FILES += [
-    'ISimpleDOMNode.tlb',
+    'dlldata.c',
+    'ISimpleDOM.h',
+    'ISimpleDOM.tlb',
+    'ISimpleDOM_i.c',
+    'ISimpleDOM_p.c',
 ]
 
 RCINCLUDE = 'AccessibleMarshal.rc'
 
 # The Windows MIDL code generator creates things like:
 #
 #   #endif !_MIDL_USE_GUIDDEF_
 #
--- a/accessible/ipc/DocAccessibleParent.cpp
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -7,65 +7,81 @@
 #include "DocAccessibleParent.h"
 #include "mozilla/a11y/Platform.h"
 #include "mozilla/dom/TabParent.h"
 #include "xpcAccessibleDocument.h"
 #include "xpcAccEvents.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 
+#if defined(XP_WIN)
+#include "AccessibleWrap.h"
+#include "Compatibility.h"
+#include "nsWinUtils.h"
+#include "RootAccessible.h"
+#endif
+
 namespace mozilla {
 namespace a11y {
+uint64_t DocAccessibleParent::sMaxDocID = 0;
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvShowEvent(const ShowEventData& aData,
                                    const bool& aFromUser)
 {
   if (mShutdown)
     return IPC_OK();
 
-  MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
+  MOZ_ASSERT(CheckDocTree());
 
   if (aData.NewTree().IsEmpty()) {
     NS_ERROR("no children being added");
     return IPC_FAIL_NO_REASON(this);
   }
 
   ProxyAccessible* parent = GetAccessible(aData.ID());
 
   // XXX This should really never happen, but sometimes we fail to fire the
   // required show events.
   if (!parent) {
     NS_ERROR("adding child to unknown accessible");
+#ifdef DEBUG
+    return IPC_FAIL(this, "unknown parent accessible");
+#else
     return IPC_OK();
+#endif
   }
 
   uint32_t newChildIdx = aData.Idx();
   if (newChildIdx > parent->ChildrenCount()) {
     NS_ERROR("invalid index to add child at");
+#ifdef DEBUG
+    return IPC_FAIL(this, "invalid index");
+#else
     return IPC_OK();
+#endif
   }
 
   uint32_t consumed = AddSubtree(parent, aData.NewTree(), 0, newChildIdx);
   MOZ_ASSERT(consumed == aData.NewTree().Length());
 
   // XXX This shouldn't happen, but if we failed to add children then the below
   // is pointless and can crash.
   if (!consumed) {
-    return IPC_OK();
+    return IPC_FAIL(this, "failed to add children");
   }
 
 #ifdef DEBUG
   for (uint32_t i = 0; i < consumed; i++) {
     uint64_t id = aData.NewTree()[i].ID();
     MOZ_ASSERT(mAccessibles.GetEntry(id));
   }
 #endif
 
-  MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
+  MOZ_ASSERT(CheckDocTree());
 
   ProxyAccessible* target = parent->ChildAt(newChildIdx);
   ProxyShowHideEvent(target, parent, true, aFromUser);
 
   if (!nsCoreUtils::AccEventObserversExist()) {
     return IPC_OK();
   }
 
@@ -132,17 +148,17 @@ DocAccessibleParent::AddSubtree(ProxyAcc
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID,
                                    const bool& aFromUser)
 {
   if (mShutdown)
     return IPC_OK();
 
-  MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
+  MOZ_ASSERT(CheckDocTree());
 
   // We shouldn't actually need this because mAccessibles shouldn't have an
   // entry for the document itself, but it doesn't hurt to be explicit.
   if (!aRootID) {
     NS_ERROR("trying to hide entire document?");
     return IPC_FAIL_NO_REASON(this);
   }
 
@@ -174,28 +190,32 @@ DocAccessibleParent::RecvHideEvent(const
     nsIDOMNode* node = nullptr;
     event = new xpcAccHideEvent(type, xpcAcc, doc, node, aFromUser, xpcParent,
                                 xpcNext, xpcPrev);
   }
 
   parent->RemoveChild(root);
   root->Shutdown();
 
-  MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
+  MOZ_ASSERT(CheckDocTree());
 
   if (event) {
     nsCoreUtils::DispatchAccEvent(Move(event));
   }
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvEvent(const uint64_t& aID, const uint32_t& aEventType)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* proxy = GetAccessible(aID);
   if (!proxy) {
     NS_ERROR("no proxy for event!");
     return IPC_OK();
   }
 
   ProxyEvent(proxy, aEventType);
 
@@ -214,16 +234,20 @@ DocAccessibleParent::RecvEvent(const uin
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvStateChangeEvent(const uint64_t& aID,
                                           const uint64_t& aState,
                                           const bool& aEnabled)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* target = GetAccessible(aID);
   if (!target) {
     NS_ERROR("we don't know about the target of a state change event!");
     return IPC_OK();
   }
 
   ProxyStateChangeEvent(target, aState, aEnabled);
 
@@ -244,16 +268,20 @@ DocAccessibleParent::RecvStateChangeEven
   nsCoreUtils::DispatchAccEvent(Move(event));
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* proxy = GetAccessible(aID);
   if (!proxy) {
     NS_ERROR("unknown caret move event target!");
     return IPC_OK();
   }
 
   ProxyCaretMoveEvent(proxy, aOffset);
 
@@ -276,16 +304,20 @@ DocAccessibleParent::RecvCaretMoveEvent(
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvTextChangeEvent(const uint64_t& aID,
                                          const nsString& aStr,
                                          const int32_t& aStart,
                                          const uint32_t& aLen,
                                          const bool& aIsInsert,
                                          const bool& aFromUser)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* target = GetAccessible(aID);
   if (!target) {
     NS_ERROR("text change event target is unknown!");
     return IPC_OK();
   }
 
   ProxyTextChangeEvent(target, aStr, aStart, aLen, aIsInsert, aFromUser);
 
@@ -306,16 +338,20 @@ DocAccessibleParent::RecvTextChangeEvent
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvSelectionEvent(const uint64_t& aID,
                                         const uint64_t& aWidgetID,
                                         const uint32_t& aType)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
   ProxyAccessible* target = GetAccessible(aID);
   ProxyAccessible* widget = GetAccessible(aWidgetID);
   if (!target || !widget) {
     NS_ERROR("invalid id in selection event");
     return IPC_OK();
   }
 
   ProxySelectionEvent(target, widget, aType);
@@ -329,78 +365,92 @@ DocAccessibleParent::RecvSelectionEvent(
   nsCoreUtils::DispatchAccEvent(Move(event));
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvRoleChangedEvent(const uint32_t& aRole)
 {
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
  if (aRole >= roles::LAST_ROLE) {
    NS_ERROR("child sent bad role in RoleChangedEvent");
    return IPC_FAIL_NO_REASON(this);
  }
 
  mRole = static_cast<a11y::role>(aRole);
  return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID)
 {
   // One document should never directly be the child of another.
   // We should always have at least an outer doc accessible in between.
   MOZ_ASSERT(aID);
   if (!aID)
-    return IPC_FAIL_NO_REASON(this);
+    return IPC_FAIL(this, "ID is 0!");
 
-  MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
+  if (mShutdown) {
+    return IPC_OK();
+  }
+
+  MOZ_ASSERT(CheckDocTree());
 
   auto childDoc = static_cast<DocAccessibleParent*>(aChildDoc);
   childDoc->Unbind();
-  bool result = AddChildDoc(childDoc, aID, false);
+  ipc::IPCResult result = AddChildDoc(childDoc, aID, false);
   MOZ_ASSERT(result);
-  MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
+  MOZ_ASSERT(CheckDocTree());
+#ifdef DEBUG
   if (!result) {
-    return IPC_FAIL_NO_REASON(this);
+    return result;
   }
-  return IPC_OK();
+#else
+  result = IPC_OK();
+#endif
+
+  return result;
 }
 
-bool
+ipc::IPCResult
 DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
                                  uint64_t aParentID, bool aCreating)
 {
   // We do not use GetAccessible here because we want to be sure to not get the
   // document it self.
   ProxyEntry* e = mAccessibles.GetEntry(aParentID);
-  if (!e)
-    return false;
+  if (!e) {
+    return IPC_FAIL(this, "binding to nonexistant proxy!");
+  }
 
   ProxyAccessible* outerDoc = e->mProxy;
   MOZ_ASSERT(outerDoc);
 
   // OuterDocAccessibles are expected to only have a document as a child.
   // However for compatibility we tolerate replacing one document with another
   // here.
   if (outerDoc->ChildrenCount() > 1 ||
       (outerDoc->ChildrenCount() == 1 && !outerDoc->ChildAt(0)->IsDoc())) {
-    return false;
+    return IPC_FAIL(this, "binding to proxy that can't be a outerDoc!");
   }
 
-  aChildDoc->mParent = outerDoc;
+  aChildDoc->SetParent(outerDoc);
   outerDoc->SetChildDoc(aChildDoc);
-  mChildDocs.AppendElement(aChildDoc);
-  aChildDoc->mParentDoc = this;
+  mChildDocs.AppendElement(aChildDoc->mActorID);
+  aChildDoc->mParentDoc = mActorID;
 
   if (aCreating) {
     ProxyCreated(aChildDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT);
   }
 
-  return true;
+  return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvShutdown()
 {
   Destroy();
 
   auto mgr = static_cast<dom::TabParent*>(Manager());
@@ -411,112 +461,204 @@ DocAccessibleParent::RecvShutdown()
   }
 
   return IPC_OK();
 }
 
 void
 DocAccessibleParent::Destroy()
 {
-  NS_ASSERTION(mChildDocs.IsEmpty(),
-               "why weren't the child docs destroyed already?");
-  MOZ_ASSERT(!mShutdown);
+  // If we are already shutdown that is because our containing tab parent is
+  // shutting down in which case we don't need to do anything.
+  if (mShutdown) {
+    return;
+  }
+
   mShutdown = true;
 
+  MOZ_DIAGNOSTIC_ASSERT(LiveDocs().Contains(mActorID));
   uint32_t childDocCount = mChildDocs.Length();
-  for (uint32_t i = childDocCount - 1; i < childDocCount; i--)
-    mChildDocs[i]->Destroy();
+  for (uint32_t i = 0; i < childDocCount; i++) {
+    for (uint32_t j = i + 1; j < childDocCount; j++) {
+      MOZ_DIAGNOSTIC_ASSERT(mChildDocs[i] != mChildDocs[j]);
+    }
+  }
+
+  // XXX This indirection through the hash map of live documents shouldn't be
+  // needed, but be paranoid for now.
+  int32_t actorID = mActorID;
+  for (uint32_t i = childDocCount - 1; i < childDocCount; i--) {
+    DocAccessibleParent* thisDoc = LiveDocs().Get(actorID);
+    MOZ_ASSERT(thisDoc);
+    if (!thisDoc) {
+      return;
+    }
+
+    thisDoc->ChildDocAt(i)->Destroy();
+  }
 
   for (auto iter = mAccessibles.Iter(); !iter.Done(); iter.Next()) {
     MOZ_ASSERT(iter.Get()->mProxy != this);
     ProxyDestroyed(iter.Get()->mProxy);
     iter.Remove();
   }
 
-  DocManager::NotifyOfRemoteDocShutdown(this);
-  ProxyDestroyed(this);
-  if (mParentDoc)
-    mParentDoc->RemoveChildDoc(this);
+  DocAccessibleParent* thisDoc = LiveDocs().Get(actorID);
+  MOZ_ASSERT(thisDoc);
+  if (!thisDoc) {
+    return;
+  }
+
+  // The code above should have already completely cleared these, but to be
+  // extra safe make sure they are cleared here.
+  thisDoc->mAccessibles.Clear();
+  thisDoc->mChildDocs.Clear();
+
+  DocManager::NotifyOfRemoteDocShutdown(thisDoc);
+  thisDoc = LiveDocs().Get(actorID);
+  MOZ_ASSERT(thisDoc);
+  if (!thisDoc) {
+    return;
+  }
+
+  ProxyDestroyed(thisDoc);
+  thisDoc = LiveDocs().Get(actorID);
+  MOZ_ASSERT(thisDoc);
+  if (!thisDoc) {
+    return;
+  }
+
+  if (DocAccessibleParent* parentDoc = thisDoc->ParentDoc())
+    parentDoc->RemoveChildDoc(thisDoc);
   else if (IsTopLevel())
     GetAccService()->RemoteDocShutdown(this);
 }
 
+DocAccessibleParent*
+DocAccessibleParent::ParentDoc() const
+{
+  if (mParentDoc == kNoParentDoc) {
+    return nullptr;
+  }
+
+  return LiveDocs().Get(mParentDoc);
+}
+
+bool
+DocAccessibleParent::CheckDocTree() const
+{
+  size_t childDocs = mChildDocs.Length();
+  for (size_t i = 0; i < childDocs; i++) {
+    const DocAccessibleParent* childDoc = ChildDocAt(i);
+    if (!childDoc || childDoc->ParentDoc() != this)
+      return false;
+
+    if (!childDoc->CheckDocTree()) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 xpcAccessibleGeneric*
 DocAccessibleParent::GetXPCAccessible(ProxyAccessible* aProxy)
 {
   xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
   MOZ_ASSERT(doc);
 
   return doc->GetXPCAccessible(aProxy);
 }
 
-bool
-DocAccessibleParent::CheckDocTreeInternal() const
+#if defined(XP_WIN)
+void
+DocAccessibleParent::MaybeInitWindowEmulation()
 {
-  size_t childDocs = mChildDocs.Length();
-  for (size_t i = 0; i < childDocs; i++) {
-    if (!mChildDocs[i] || mChildDocs[i]->mParentDoc != this)
-      return false;
+  if (!nsWinUtils::IsWindowEmulationStarted()) {
+    return;
+  }
+
+  // XXX get the bounds from the tabParent instead of poking at accessibles
+  // which might not exist yet.
+  Accessible* outerDoc = OuterDocOfRemoteBrowser();
+  if (!outerDoc) {
+    return;
+  }
+
+  RootAccessible* rootDocument = outerDoc->RootAccessible();
+  MOZ_ASSERT(rootDocument);
 
-    if (!mChildDocs[i]->CheckDocTreeInternal()) {
-      return false;
+  bool isActive = true;
+  nsIntRect rect(CW_USEDEFAULT, CW_USEDEFAULT, 0, 0);
+  if (Compatibility::IsDolphin()) {
+    rect = Bounds();
+    nsIntRect rootRect = rootDocument->Bounds();
+    rect.x = rootRect.x - rect.x;
+    rect.y -= rootRect.y;
+
+    auto tab = static_cast<dom::TabParent*>(Manager());
+    tab->GetDocShellIsActive(&isActive);
+  }
+
+  IAccessibleHolder hWndAccHolder;
+  HWND parentWnd = reinterpret_cast<HWND>(rootDocument->GetNativeWindow());
+  HWND hWnd = nsWinUtils::CreateNativeWindow(kClassNameTabContent,
+                                             parentWnd, rect.x, rect.y,
+                                             rect.width, rect.height,
+                                             isActive);
+  if (hWnd) {
+    // Attach accessible document to the emulated native window
+    ::SetPropW(hWnd, kPropNameDocAccParent, (HANDLE)this);
+    SetEmulatedWindowHandle(hWnd);
+    IAccessible* rawHWNDAcc = nullptr;
+    if (SUCCEEDED(::AccessibleObjectFromWindow(hWnd, OBJID_WINDOW,
+                                               IID_IAccessible,
+                                               (void**)&rawHWNDAcc))) {
+      hWndAccHolder.Set(IAccessibleHolder::COMPtrType(rawHWNDAcc));
     }
   }
 
-  return true;
+  Unused << SendEmulatedWindow(reinterpret_cast<uintptr_t>(mEmulatedWindowHandle),
+                               hWndAccHolder);
 }
 
-const DocAccessibleParent*
-DocAccessibleParent::CheckTopDoc() const
-{
-  const DocAccessibleParent* doc = this;
-  while (doc->ParentDoc()) {
-    doc = doc->ParentDoc();
-  }
-
-  MOZ_DIAGNOSTIC_ASSERT(doc->mTopLevel);
-  MOZ_DIAGNOSTIC_ASSERT(DocManager::TopLevelRemoteDocs()->Contains(doc));
-
-  return doc;
-}
-
-bool
-DocAccessibleParent::CheckDocTree() const
-{
-  return CheckTopDoc()->CheckDocTreeInternal();
-}
-
-#if defined(XP_WIN)
 /**
  * @param aCOMProxy COM Proxy to the document in the content process.
  */
 void
-DocAccessibleParent::SetCOMProxy(const RefPtr<IAccessible>& aCOMProxy)
+DocAccessibleParent::SendParentCOMProxy()
 {
-  SetCOMInterface(aCOMProxy);
-
   // Make sure that we're not racing with a tab shutdown
   auto tab = static_cast<dom::TabParent*>(Manager());
   MOZ_ASSERT(tab);
   if (tab->IsDestroyed()) {
     return;
   }
 
   Accessible* outerDoc = OuterDocOfRemoteBrowser();
-  MOZ_ASSERT(outerDoc);
+  if (!outerDoc) {
+    return;
+  }
 
   IAccessible* rawNative = nullptr;
-  if (outerDoc) {
-    outerDoc->GetNativeInterface((void**) &rawNative);
-    MOZ_ASSERT(rawNative);
-  }
+  outerDoc->GetNativeInterface((void**) &rawNative);
+  MOZ_ASSERT(rawNative);
 
   IAccessibleHolder::COMPtrType ptr(rawNative);
   IAccessibleHolder holder(Move(ptr));
-  Unused << SendParentCOMProxy(holder);
+  Unused << PDocAccessibleParent::SendParentCOMProxy(holder);
+}
+
+void
+DocAccessibleParent::SetEmulatedWindowHandle(HWND aWindowHandle)
+{
+  if (!aWindowHandle && mEmulatedWindowHandle && IsTopLevel()) {
+    ::DestroyWindow(mEmulatedWindowHandle);
+  }
+  mEmulatedWindowHandle = aWindowHandle;
 }
 
 mozilla::ipc::IPCResult
 DocAccessibleParent::RecvGetWindowedPluginIAccessible(
       const WindowsHandle& aHwnd, IAccessibleHolder* aPluginCOMProxy)
 {
 #if defined(MOZ_CONTENT_SANDBOX)
   // We don't actually want the accessible object for aHwnd, but rather the
--- a/accessible/ipc/DocAccessibleParent.h
+++ b/accessible/ipc/DocAccessibleParent.h
@@ -23,31 +23,53 @@ class xpcAccessibleGeneric;
  * These objects live in the main process and comunicate with and represent
  * an accessible document in a content process.
  */
 class DocAccessibleParent : public ProxyAccessible,
     public PDocAccessibleParent
 {
 public:
   DocAccessibleParent() :
-    ProxyAccessible(this), mParentDoc(nullptr),
+    ProxyAccessible(this), mParentDoc(kNoParentDoc),
     mTopLevel(false), mShutdown(false)
-  { MOZ_COUNT_CTOR_INHERITED(DocAccessibleParent, ProxyAccessible); }
+#if defined(XP_WIN)
+                                      , mEmulatedWindowHandle(nullptr)
+#endif // defined(XP_WIN)
+  {
+    MOZ_COUNT_CTOR_INHERITED(DocAccessibleParent, ProxyAccessible);
+    sMaxDocID++;
+    mActorID = sMaxDocID;
+    MOZ_ASSERT(!LiveDocs().Get(mActorID));
+    LiveDocs().Put(mActorID, this);
+  }
   ~DocAccessibleParent()
   {
+    LiveDocs().Remove(mActorID);
     MOZ_COUNT_DTOR_INHERITED(DocAccessibleParent, ProxyAccessible);
     MOZ_ASSERT(mChildDocs.Length() == 0);
     MOZ_ASSERT(!ParentDoc());
   }
 
   void SetTopLevel() { mTopLevel = true; }
   bool IsTopLevel() const { return mTopLevel; }
 
   bool IsShutdown() const { return mShutdown; }
 
+  /**
+   * Mark this actor as shutdown without doing any cleanup.  This should only
+   * be called on actors that have just been initialized, so probably only from
+   * RecvPDocAccessibleConstructor.
+   */
+  void MarkAsShutdown()
+  {
+    MOZ_ASSERT(mChildDocs.IsEmpty());
+    MOZ_ASSERT(mAccessibles.Count() == 0);
+    mShutdown = true;
+  }
+
   /*
    * Called when a message from a document in a child process notifies the main
    * process it is firing an event.
    */
   virtual mozilla::ipc::IPCResult RecvEvent(const uint64_t& aID, const uint32_t& aType)
     override;
 
   virtual mozilla::ipc::IPCResult RecvShowEvent(const ShowEventData& aData, const bool& aFromUser)
@@ -75,53 +97,56 @@ public:
   virtual mozilla::ipc::IPCResult RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID) override;
 
   void Unbind()
   {
     if (DocAccessibleParent* parent = ParentDoc()) {
       parent->RemoveChildDoc(this);
     }
 
-    mParent = nullptr;
+    SetParent(nullptr);
   }
 
   virtual mozilla::ipc::IPCResult RecvShutdown() override;
   void Destroy();
   virtual void ActorDestroy(ActorDestroyReason aWhy) override
   {
-    if (mShutdown) {
-      return;
-    }
-
-    MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
-    Destroy();
+    MOZ_ASSERT(CheckDocTree());
+    if (!mShutdown)
+      Destroy();
   }
 
   /*
    * Return the main processes representation of the parent document (if any)
    * of the document this object represents.
    */
-  DocAccessibleParent* ParentDoc() const { return mParentDoc; }
+  DocAccessibleParent* ParentDoc() const;
+  static const uint64_t kNoParentDoc = UINT64_MAX;
 
   /*
    * Called when a document in a content process notifies the main process of a
    * new child document.
    */
-  bool AddChildDoc(DocAccessibleParent* aChildDoc, uint64_t aParentID,
-                   bool aCreating = true);
+  ipc::IPCResult AddChildDoc(DocAccessibleParent* aChildDoc,
+                             uint64_t aParentID, bool aCreating = true);
 
   /*
    * Called when the document in the content process this object represents
    * notifies the main process a child document has been removed.
    */
   void RemoveChildDoc(DocAccessibleParent* aChildDoc)
   {
-    aChildDoc->Parent()->ClearChildDoc(aChildDoc);
-    mChildDocs.RemoveElement(aChildDoc);
-    aChildDoc->mParentDoc = nullptr;
+    ProxyAccessible* parent = aChildDoc->Parent();
+    MOZ_ASSERT(parent);
+    if (parent) {
+      aChildDoc->Parent()->ClearChildDoc(aChildDoc);
+    }
+    DebugOnly<bool> result = mChildDocs.RemoveElement(aChildDoc->mActorID);
+    aChildDoc->mParentDoc = kNoParentDoc;
+    MOZ_ASSERT(result);
     MOZ_ASSERT(aChildDoc->mChildDocs.Length() == 0);
   }
 
   void RemoveAccessible(ProxyAccessible* aAccessible)
   {
     MOZ_DIAGNOSTIC_ASSERT(mAccessibles.GetEntry(aAccessible->ID()));
     mAccessibles.RemoveEntry(aAccessible->ID());
   }
@@ -138,23 +163,33 @@ public:
     return e ? e->mProxy : nullptr;
   }
 
   const ProxyAccessible* GetAccessible(uintptr_t aID) const
     { return const_cast<DocAccessibleParent*>(this)->GetAccessible(aID); }
 
   size_t ChildDocCount() const { return mChildDocs.Length(); }
   const DocAccessibleParent* ChildDocAt(size_t aIdx) const
-    { return mChildDocs[aIdx]; }
+  { return const_cast<DocAccessibleParent*>(this)->ChildDocAt(aIdx); }
+  DocAccessibleParent* ChildDocAt(size_t aIdx)
+    { return LiveDocs().Get(mChildDocs[aIdx]); }
 
 #if defined(XP_WIN)
-  void SetCOMProxy(const RefPtr<IAccessible>& aCOMProxy);
+  void MaybeInitWindowEmulation();
+  void SendParentCOMProxy();
 
   virtual mozilla::ipc::IPCResult RecvGetWindowedPluginIAccessible(
       const WindowsHandle& aHwnd, IAccessibleHolder* aPluginCOMProxy) override;
+
+  /**
+   * Set emulated native window handle for a document.
+   * @param aWindowHandle emulated native window handle
+   */
+  void SetEmulatedWindowHandle(HWND aWindowHandle);
+  HWND GetEmulatedWindowHandle() const { return mEmulatedWindowHandle; }
 #endif
 
 private:
 
   class ProxyEntry : public PLDHashEntryHdr
   {
   public:
     explicit ProxyEntry(const void*) : mProxy(nullptr) {}
@@ -175,29 +210,41 @@ private:
     enum { ALLOW_MEMMOVE = true };
 
     ProxyAccessible* mProxy;
   };
 
   uint32_t AddSubtree(ProxyAccessible* aParent,
                       const nsTArray<AccessibleData>& aNewTree, uint32_t aIdx,
                       uint32_t aIdxInParent);
+  MOZ_MUST_USE bool CheckDocTree() const;
   xpcAccessibleGeneric* GetXPCAccessible(ProxyAccessible* aProxy);
-  MOZ_MUST_USE bool CheckDocTree() const;
-  MOZ_MUST_USE bool CheckDocTreeInternal() const;
-  const DocAccessibleParent* CheckTopDoc() const;
+
+  nsTArray<uint64_t> mChildDocs;
+  uint64_t mParentDoc;
 
-  nsTArray<DocAccessibleParent*> mChildDocs;
-  DocAccessibleParent* mParentDoc;
+#if defined(XP_WIN)
+  // The handle associated with the emulated window that contains this document
+  HWND mEmulatedWindowHandle;
+#endif
 
   /*
    * Conceptually this is a map from IDs to proxies, but we store the ID in the
    * proxy object so we can't use a real map.
    */
   nsTHashtable<ProxyEntry> mAccessibles;
+  uint64_t mActorID;
   bool mTopLevel;
   bool mShutdown;
+
+  static uint64_t sMaxDocID;
+  static nsDataHashtable<nsUint64HashKey, DocAccessibleParent*>&
+    LiveDocs()
+    {
+      static nsDataHashtable<nsUint64HashKey, DocAccessibleParent*> sLiveDocs;
+      return sLiveDocs;
+    }
 };
 
 }
 }
 
 #endif
--- a/accessible/ipc/ProxyAccessibleBase.cpp
+++ b/accessible/ipc/ProxyAccessibleBase.cpp
@@ -20,34 +20,34 @@
 namespace mozilla {
 namespace a11y {
 
 template <class Derived>
 void
 ProxyAccessibleBase<Derived>::Shutdown()
 {
   MOZ_DIAGNOSTIC_ASSERT(!IsDoc());
-  NS_ASSERTION(!mOuterDoc, "Why do we still have a child doc?");
   xpcAccessibleDocument* xpcDoc =
     GetAccService()->GetCachedXPCDocument(Document());
   if (xpcDoc) {
     xpcDoc->NotifyOfShutdown(static_cast<Derived*>(this));
   }
 
   // XXX Ideally  this wouldn't be necessary, but it seems OuterDoc accessibles
   // can be destroyed before the doc they own.
+  uint32_t childCount = mChildren.Length();
   if (!mOuterDoc) {
-    uint32_t childCount = mChildren.Length();
     for (uint32_t idx = 0; idx < childCount; idx++)
       mChildren[idx]->Shutdown();
   } else {
-    if (mChildren.Length() != 1)
-      MOZ_CRASH("outer doc doesn't own adoc!");
-
-    mChildren[0]->AsDoc()->Unbind();
+    if (childCount > 1) {
+      MOZ_CRASH("outer doc has too many documents!");
+    } else if (childCount == 1) {
+      mChildren[0]->AsDoc()->Unbind();
+    }
   }
 
   mChildren.Clear();
   ProxyDestroyed(static_cast<Derived*>(this));
   mDoc->RemoveAccessible(static_cast<Derived*>(this));
 }
 
 template <class Derived>
@@ -71,19 +71,17 @@ void
 ProxyAccessibleBase<Derived>::ClearChildDoc(DocAccessibleParent* aChildDoc)
 {
   MOZ_ASSERT(aChildDoc);
   // This is possible if we're replacing one document with another: Doc 1
   // has not had a chance to remove itself, but was already replaced by Doc 2
   // in SetChildDoc(). This could result in two subsequent calls to
   // ClearChildDoc() even though mChildren.Length() == 1.
   MOZ_ASSERT(mChildren.Length() <= 1);
-  if (mChildren.RemoveElement(aChildDoc)) {
-    mOuterDoc = false;
-  }
+  mChildren.RemoveElement(aChildDoc);
 }
 
 template <class Derived>
 bool
 ProxyAccessibleBase<Derived>::MustPruneChildren() const
 {
   // this is the equivalent to nsAccUtils::MustPrune for proxies and should be
   // kept in sync with that.
@@ -164,12 +162,53 @@ ProxyAccessibleBase<Derived>::OuterDocOf
   if (!frame)
     return nullptr;
 
   DocAccessible* chromeDoc = GetExistingDocAccessible(frame->OwnerDoc());
 
   return chromeDoc ? chromeDoc->GetAccessible(frame) : nullptr;
 }
 
+template<class Derived>
+void
+ProxyAccessibleBase<Derived>::SetParent(Derived* aParent)
+{
+  MOZ_ASSERT(IsDoc(), "we should only reparent documents");
+  if (!aParent) {
+    mParent = kNoParent;
+  } else {
+    MOZ_ASSERT(!aParent->IsDoc());
+    mParent = aParent->ID();
+  }
+}
+
+template<class Derived>
+Derived*
+ProxyAccessibleBase<Derived>::Parent() const
+{
+  if (mParent == kNoParent) {
+    return nullptr;
+  }
+
+  // if we are not a document then are parent is another proxy in the same
+  // document.  That means we can just ask our document for the proxy with our
+  // parent id.
+  if (!IsDoc()) {
+    return Document()->GetAccessible(mParent);
+  }
+
+  // If we are a top level document then our parent is not a proxy.
+  if (AsDoc()->IsTopLevel()) {
+    return nullptr;
+  }
+
+  // Finally if we are a non top level document then our parent id is for a
+  // proxy in our parent document so get the proxy from there.
+  DocAccessibleParent* parentDoc = AsDoc()->ParentDoc();
+  MOZ_ASSERT(parentDoc);
+  MOZ_ASSERT(mParent);
+  return parentDoc->GetAccessible(mParent);
+}
+
 template class ProxyAccessibleBase<ProxyAccessible>;
 
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/ipc/ProxyAccessibleBase.h
+++ b/accessible/ipc/ProxyAccessibleBase.h
@@ -85,17 +85,17 @@ public:
    * Remove The given child.
    */
   void RemoveChild(Derived* aChild)
     { mChildren.RemoveElement(aChild); }
 
   /**
    * Return the proxy for the parent of the wrapped accessible.
    */
-  Derived* Parent() const { return mParent; }
+  Derived* Parent() const;
 
   Accessible* OuterDocOfRemoteBrowser() const;
 
   /**
    * Get the role of the accessible we're proxying.
    */
   role Role() const { return mRole; }
 
@@ -153,39 +153,42 @@ public:
         mRole == roles::GRID_CELL ||
         mRole == roles::MATHML_CELL);
   }
 
 protected:
   ProxyAccessibleBase(uint64_t aID, Derived* aParent,
                       DocAccessibleParent* aDoc, role aRole,
                       uint32_t aInterfaces)
-    : mParent(aParent)
+    : mParent(aParent->ID())
     , mDoc(aDoc)
     , mWrapper(0)
     , mID(aID)
     , mRole(aRole)
     , mOuterDoc(false)
     , mIsDoc(false)
     , mHasValue(aInterfaces & Interfaces::VALUE)
     , mIsHyperLink(aInterfaces & Interfaces::HYPERLINK)
     , mIsHyperText(aInterfaces & Interfaces::HYPERTEXT)
   {
   }
 
   explicit ProxyAccessibleBase(DocAccessibleParent* aThisAsDoc) :
-    mParent(nullptr), mDoc(aThisAsDoc), mWrapper(0), mID(0),
+    mParent(kNoParent), mDoc(aThisAsDoc), mWrapper(0), mID(0),
     mRole(roles::DOCUMENT), mOuterDoc(false), mIsDoc(true), mHasValue(false),
     mIsHyperLink(false), mIsHyperText(false)
   {}
 
 protected:
-  Derived* mParent;
+  void SetParent(Derived* aParent);
 
 private:
+  uintptr_t mParent;
+  static const uintptr_t kNoParent = UINTPTR_MAX;
+
   friend Derived;
 
   nsTArray<Derived*> mChildren;
   DocAccessibleParent* mDoc;
   uintptr_t mWrapper;
   uint64_t mID;
 
 protected:
--- a/accessible/ipc/win/DocAccessibleChild.cpp
+++ b/accessible/ipc/win/DocAccessibleChild.cpp
@@ -13,16 +13,17 @@
 
 namespace mozilla {
 namespace a11y {
 
 static StaticAutoPtr<PlatformChild> sPlatformChild;
 
 DocAccessibleChild::DocAccessibleChild(DocAccessible* aDoc)
   : DocAccessibleChildBase(aDoc)
+  , mEmulatedWindowHandle(nullptr)
   , mIsRemoteConstructed(false)
 {
   MOZ_COUNT_CTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
   if (!sPlatformChild) {
     sPlatformChild = new PlatformChild();
     ClearOnShutdown(&sPlatformChild, ShutdownPhase::Shutdown);
   }
 }
@@ -55,16 +56,30 @@ DocAccessibleChild::RecvParentCOMProxy(c
     mDeferredEvents[i]->Dispatch();
   }
 
   mDeferredEvents.Clear();
 
   return IPC_OK();
 }
 
+ipc::IPCResult
+DocAccessibleChild::RecvEmulatedWindow(const WindowsHandle& aEmulatedWindowHandle,
+                                       const IAccessibleHolder& aEmulatedWindowCOMProxy)
+{
+  mEmulatedWindowHandle = reinterpret_cast<HWND>(aEmulatedWindowHandle);
+  if (!aEmulatedWindowCOMProxy.IsNull()) {
+    MOZ_ASSERT(!mEmulatedWindowProxy);
+    mEmulatedWindowProxy.reset(
+      const_cast<IAccessibleHolder&>(aEmulatedWindowCOMProxy).Release());
+  }
+
+  return IPC_OK();
+}
+
 void
 DocAccessibleChild::PushDeferredEvent(UniquePtr<DeferredEvent> aEvent)
 {
   DocAccessibleChild* topLevelIPCDoc = nullptr;
 
   if (mDoc && mDoc->IsRoot()) {
     topLevelIPCDoc = this;
   } else {
--- a/accessible/ipc/win/DocAccessibleChild.h
+++ b/accessible/ipc/win/DocAccessibleChild.h
@@ -24,16 +24,22 @@ class DocAccessibleChild : public DocAcc
 public:
   explicit DocAccessibleChild(DocAccessible* aDoc);
   ~DocAccessibleChild();
 
   virtual void Shutdown() override;
 
   virtual ipc::IPCResult
   RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy) override;
+  virtual ipc::IPCResult
+    RecvEmulatedWindow(const WindowsHandle& aEmulatedWindowHandle,
+                       const IAccessibleHolder& aEmulatedWindowCOMProxy) override;
+
+  HWND GetEmulatedWindowHandle() const { return mEmulatedWindowHandle; }
+  IAccessible* GetEmulatedWindowIAccessible() const { return mEmulatedWindowProxy.get(); }
 
   IAccessible* GetParentIAccessible() const { return mParentProxy.get(); }
 
   bool SendEvent(const uint64_t& aID, const uint32_t& type);
   bool SendHideEvent(const uint64_t& aRootID, const bool& aFromUser);
   bool SendStateChangeEvent(const uint64_t& aID, const uint64_t& aState,
                             const bool& aEnabled);
   bool SendCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset);
@@ -304,15 +310,17 @@ private:
     void Dispatch(DocAccessibleChild* aIPCDoc) override
     {
       aIPCDoc->Shutdown();
     }
   };
 
   bool mIsRemoteConstructed;
   mscom::ProxyUniquePtr<IAccessible> mParentProxy;
+  mscom::ProxyUniquePtr<IAccessible> mEmulatedWindowProxy;
   nsTArray<UniquePtr<DeferredEvent>> mDeferredEvents;
+  HWND mEmulatedWindowHandle;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_DocAccessibleChild_h
--- a/accessible/ipc/win/PDocAccessible.ipdl
+++ b/accessible/ipc/win/PDocAccessible.ipdl
@@ -62,14 +62,16 @@ parent:
    */
   async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
 
   sync GetWindowedPluginIAccessible(WindowsHandle aHwnd)
     returns (IAccessibleHolder aPluginCOMProxy);
 
 child:
   async ParentCOMProxy(IAccessibleHolder aParentCOMProxy);
+  async EmulatedWindow(WindowsHandle aEmulatedWindowHandle,
+                       IAccessibleHolder aEmulatedWindowCOMProxy);
 
   async __delete__();
 };
 
 }
 }
--- a/accessible/ipc/win/PlatformChild.cpp
+++ b/accessible/ipc/win/PlatformChild.cpp
@@ -41,20 +41,28 @@ static const mozilla::mscom::ArrayData s
 // Type libraries are thread-neutral, so we can register those from any
 // apartment. OTOH, proxies must be registered from within the apartment where
 // we intend to instantiate them. Therefore RegisterProxy() must be called
 // via EnsureMTA.
 PlatformChild::PlatformChild()
   : mAccTypelib(mozilla::mscom::RegisterTypelib(L"oleacc.dll",
         mozilla::mscom::RegistrationFlags::eUseSystemDirectory))
   , mMiscTypelib(mozilla::mscom::RegisterTypelib(L"Accessible.tlb"))
+  , mSdnTypelib(mozilla::mscom::RegisterTypelib(L"AccessibleMarshal.dll"))
 {
   mozilla::mscom::InterceptorLog::Init();
   mozilla::mscom::RegisterArrayData(sPlatformChildArrayData);
 
+
+  UniquePtr<mozilla::mscom::RegisteredProxy> customProxy;
+  mozilla::mscom::EnsureMTA([&customProxy]() -> void {
+    customProxy = Move(mozilla::mscom::RegisterProxy());
+  });
+  mCustomProxy = Move(customProxy);
+
   UniquePtr<mozilla::mscom::RegisteredProxy> ia2Proxy;
   mozilla::mscom::EnsureMTA([&ia2Proxy]() -> void {
     ia2Proxy = Move(mozilla::mscom::RegisterProxy(L"ia2marshal.dll"));
   });
   mIA2Proxy = Move(ia2Proxy);
 }
 
 } // namespace a11y
--- a/accessible/ipc/win/PlatformChild.h
+++ b/accessible/ipc/win/PlatformChild.h
@@ -18,18 +18,20 @@ public:
   PlatformChild();
 
   PlatformChild(PlatformChild&) = delete;
   PlatformChild(PlatformChild&&) = delete;
   PlatformChild& operator=(PlatformChild&) = delete;
   PlatformChild& operator=(PlatformChild&&) = delete;
 
 private:
+  UniquePtr<mozilla::mscom::RegisteredProxy> mCustomProxy;
   UniquePtr<mozilla::mscom::RegisteredProxy> mIA2Proxy;
   UniquePtr<mozilla::mscom::RegisteredProxy> mAccTypelib;
   UniquePtr<mozilla::mscom::RegisteredProxy> mMiscTypelib;
+  UniquePtr<mozilla::mscom::RegisteredProxy> mSdnTypelib;
 };
 
 } // namespace mozilla
 } // namespace a11y
 
 #endif // mozilla_a11y_PlatformChild_h
 
--- a/accessible/ipc/win/ProxyAccessible.cpp
+++ b/accessible/ipc/win/ProxyAccessible.cpp
@@ -1,16 +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 "Accessible2.h"
 #include "ProxyAccessible.h"
+#include "ia2AccessibleRelation.h"
 #include "ia2AccessibleValue.h"
 #include "IGeckoCustom.h"
 #include "mozilla/a11y/DocAccessibleParent.h"
 #include "DocAccessible.h"
 #include "mozilla/a11y/DocManager.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/Unused.h"
@@ -75,16 +76,22 @@ struct InterfaceIID<IAccessibleHyperlink
 };
 
 template<>
 struct InterfaceIID<IGeckoCustom>
 {
   static REFIID Value() { return IID_IGeckoCustom; }
 };
 
+template<>
+struct InterfaceIID<IAccessible2_2>
+{
+  static REFIID Value() { return IID_IAccessible2_2; }
+};
+
 /**
  * Get the COM proxy for this proxy accessible and QueryInterface it with the
  * correct IID
  */
 template<typename Interface>
 static already_AddRefed<Interface>
 QueryInterface(const ProxyAccessible* aProxy)
 {
@@ -150,16 +157,33 @@ ProxyAccessible::Value(nsString& aValue)
   HRESULT hr = acc->get_accValue(kChildIdSelf, &result);
   _bstr_t resultWrap(result, false);
   if (FAILED(hr)) {
     return;
   }
   aValue = (wchar_t*)resultWrap;
 }
 
+double
+ProxyAccessible::Step()
+{
+  RefPtr<IGeckoCustom> custom = QueryInterface<IGeckoCustom>(this);
+  if (!custom) {
+    return 0;
+  }
+
+  double increment;
+  HRESULT hr = custom->get_minimumIncrement(&increment);
+  if (FAILED(hr)) {
+    return 0;
+  }
+
+  return increment;
+}
+
 void
 ProxyAccessible::Description(nsString& aDesc) const
 {
   aDesc.Truncate();
   RefPtr<IAccessible> acc;
   if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
     return;
   }
@@ -171,28 +195,27 @@ ProxyAccessible::Description(nsString& a
     return;
   }
   aDesc = (wchar_t*)resultWrap;
 }
 
 uint64_t
 ProxyAccessible::State() const
 {
-  uint64_t state = 0;
-  RefPtr<IAccessible> acc;
-  if (!GetCOMInterface((void**)getter_AddRefs(acc))) {
-    return state;
+  RefPtr<IGeckoCustom> custom = QueryInterface<IGeckoCustom>(this);
+  if (!custom) {
+    return 0;
   }
 
-  VARIANT varState;
-  HRESULT hr = acc->get_accState(kChildIdSelf, &varState);
+  uint64_t state;
+  HRESULT hr = custom->get_mozState(&state);
   if (FAILED(hr)) {
-    return state;
+    return 0;
   }
-  return uint64_t(varState.lVal);
+  return state;
 }
 
 nsIntRect
 ProxyAccessible::Bounds()
 {
   nsIntRect rect;
 
   RefPtr<IAccessible> acc;
@@ -311,16 +334,17 @@ ConvertBSTRAttributesToArray(const nsASt
         tokens[eName].Truncate();
         tokens[eValue].Truncate();
         ++itr;
         continue;
       default:
         break;
     }
     tokens[state] += *itr;
+    ++itr;
   }
   return true;
 }
 
 void
 ProxyAccessible::Attributes(nsTArray<Attribute>* aAttrs) const
 {
   aAttrs->Clear();
@@ -342,16 +366,54 @@ ProxyAccessible::Attributes(nsTArray<Att
     return;
   }
 
   ConvertBSTRAttributesToArray(nsDependentString((wchar_t*)attrs,
                                                  attrsWrap.length()),
                                aAttrs);
 }
 
+nsTArray<ProxyAccessible*>
+ProxyAccessible::RelationByType(RelationType aType) const
+{
+  RefPtr<IAccessible2_2> acc = QueryInterface<IAccessible2_2>(this);
+  if (!acc) {
+    nsTArray<ProxyAccessible*>();
+  }
+
+  _bstr_t relationType;
+  for (uint32_t idx = 0; idx < ArrayLength(sRelationTypePairs); idx++) {
+    if (aType == sRelationTypePairs[idx].first) {
+      relationType = sRelationTypePairs[idx].second;
+      break;
+    }
+  }
+
+  if (!relationType) {
+    nsTArray<ProxyAccessible*>();
+  }
+
+  IUnknown** targets;
+  long nTargets = 0;
+  HRESULT hr = acc->get_relationTargetsOfType(relationType, 0, &targets, &nTargets);
+  if (FAILED(hr)) {
+    nsTArray<ProxyAccessible*>();
+  }
+
+  nsTArray<ProxyAccessible*> proxies;
+  for (long idx = 0; idx < nTargets; idx++) {
+    IUnknown* target = targets[idx];
+    proxies.AppendElement(GetProxyFor(Document(), target));
+    target->Release();
+  }
+  CoTaskMemFree(targets);
+
+  return Move(proxies);
+}
+
 double
 ProxyAccessible::CurValue()
 {
   RefPtr<IAccessibleValue> acc = QueryInterface<IAccessibleValue>(this);
   if (!acc) {
     return UnspecifiedNaN<double>();
   }
 
@@ -701,10 +763,28 @@ ProxyAccessible::AnchorAt(uint32_t aIdx)
   }
 
   MOZ_ASSERT(anchor.vt == VT_UNKNOWN);
   ProxyAccessible* proxyAnchor = GetProxyFor(Document(), anchor.punkVal);
   anchor.punkVal->Release();
   return proxyAnchor;
 }
 
+void
+ProxyAccessible::DOMNodeID(nsString& aID)
+{
+  aID.Truncate();
+  RefPtr<IGeckoCustom> custom = QueryInterface<IGeckoCustom>(this);
+  if (!custom) {
+    return;
+  }
+
+  BSTR result;
+  HRESULT hr = custom->get_DOMNodeID(&result);
+  _bstr_t resultWrap(result, false);
+  if (FAILED(hr)) {
+    return;
+  }
+  aID = (wchar_t*)resultWrap;
+}
+
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/ipc/win/ProxyAccessible.h
+++ b/accessible/ipc/win/ProxyAccessible.h
@@ -34,25 +34,24 @@ public:
   ~ProxyAccessible()
   {
     MOZ_COUNT_DTOR(ProxyAccessible);
   }
 
 #include "mozilla/a11y/ProxyAccessibleShared.h"
 
   bool GetCOMInterface(void** aOutAccessible) const;
+  void SetCOMInterface(const RefPtr<IAccessible>& aIAccessible)
+  { mCOMProxy = aIAccessible; }
 
 protected:
   explicit ProxyAccessible(DocAccessibleParent* aThisAsDoc)
     : ProxyAccessibleBase(aThisAsDoc)
   { MOZ_COUNT_CTOR(ProxyAccessible); }
 
-  void SetCOMInterface(const RefPtr<IAccessible>& aIAccessible)
-  { mCOMProxy = aIAccessible; }
-
 private:
   RefPtr<IAccessible> mCOMProxy;
 };
 
 }
 }
 
 #endif
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -10,16 +10,20 @@
 
 const {utils: Cu, interfaces: Ci} = Components;
 
 this.EXPORTED_SYMBOLS = ['AccessFu']; // jshint ignore:line
 
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/accessibility/Utils.jsm');
 
+if (Utils.MozBuildApp === 'mobile/android') {
+  Cu.import('resource://gre/modules/Messaging.jsm');
+}
+
 const ACCESSFU_DISABLE = 0; // jshint ignore:line
 const ACCESSFU_ENABLE = 1;
 const ACCESSFU_AUTO = 2;
 
 const SCREENREADER_SETTING = 'accessibility.screenreader';
 const QUICKNAV_MODES_PREF = 'accessibility.accessfu.quicknav_modes';
 const QUICKNAV_INDEX_PREF = 'accessibility.accessfu.quicknav_index';
 
@@ -27,31 +31,19 @@ this.AccessFu = { // jshint ignore:line
   /**
    * Initialize chrome-layer accessibility functionality.
    * If accessibility is enabled on the platform, then a special accessibility
    * mode is started.
    */
   attach: function attach(aWindow) {
     Utils.init(aWindow);
 
-    try {
-      Services.androidBridge.dispatch('Accessibility:Ready');
-      Services.obs.addObserver(this, 'Accessibility:Settings', false);
-    } catch (x) {
-      // Not on Android
-      if (aWindow.navigator.mozSettings) {
-        let lock = aWindow.navigator.mozSettings.createLock();
-        let req = lock.get(SCREENREADER_SETTING);
-        req.addEventListener('success', () => {
-          this._systemPref = req.result[SCREENREADER_SETTING];
-          this._enableOrDisable();
-        });
-        aWindow.navigator.mozSettings.addObserver(
-          SCREENREADER_SETTING, this.handleEvent);
-      }
+    if (Utils.MozBuildApp === 'mobile/android') {
+      EventDispatcher.instance.dispatch('Accessibility:Ready');
+      EventDispatcher.instance.registerListener(this, 'Accessibility:Settings');
     }
 
     this._activatePref = new PrefCache(
       'accessibility.accessfu.activate', this._enableOrDisable.bind(this));
 
     this._enableOrDisable();
   },
 
@@ -59,20 +51,17 @@ this.AccessFu = { // jshint ignore:line
    * Shut down chrome-layer accessibility functionality from the outside.
    */
   detach: function detach() {
     // Avoid disabling twice.
     if (this._enabled) {
       this._disable();
     }
     if (Utils.MozBuildApp === 'mobile/android') {
-      Services.obs.removeObserver(this, 'Accessibility:Settings');
-    } else if (Utils.win.navigator.mozSettings) {
-      Utils.win.navigator.mozSettings.removeObserver(
-        SCREENREADER_SETTING, this.handleEvent);
+      EventDispatcher.instance.unregisterListener(this, 'Accessibility:Settings');
     }
     delete this._activatePref;
     Utils.uninit();
   },
 
   /**
    * A lazy getter for event handler that binds the scope to AccessFu object.
    */
@@ -128,26 +117,31 @@ this.AccessFu = { // jshint ignore:line
     this._notifyOutputPref =
       new PrefCache('accessibility.accessfu.notify_output');
 
 
     this.Input.start();
     Output.start();
     PointerAdapter.start();
 
+    if (Utils.MozBuildApp === 'mobile/android') {
+      EventDispatcher.instance.registerListener(this, [
+        'Accessibility:ActivateObject',
+        'Accessibility:Focus',
+        'Accessibility:LongPress',
+        'Accessibility:MoveByGranularity',
+        'Accessibility:NextObject',
+        'Accessibility:PreviousObject',
+        'Accessibility:ScrollBackward',
+        'Accessibility:ScrollForward',
+      ]);
+    }
+
     Services.obs.addObserver(this, 'remote-browser-shown', false);
     Services.obs.addObserver(this, 'inprocess-browser-shown', false);
-    Services.obs.addObserver(this, 'Accessibility:NextObject', false);
-    Services.obs.addObserver(this, 'Accessibility:PreviousObject', false);
-    Services.obs.addObserver(this, 'Accessibility:Focus', false);
-    Services.obs.addObserver(this, 'Accessibility:ActivateObject', false);
-    Services.obs.addObserver(this, 'Accessibility:LongPress', false);
-    Services.obs.addObserver(this, 'Accessibility:ScrollForward', false);
-    Services.obs.addObserver(this, 'Accessibility:ScrollBackward', false);
-    Services.obs.addObserver(this, 'Accessibility:MoveByGranularity', false);
     Utils.win.addEventListener('TabOpen', this);
     Utils.win.addEventListener('TabClose', this);
     Utils.win.addEventListener('TabSelect', this);
 
     if (this.readyCallback) {
       this.readyCallback();
       delete this.readyCallback;
     }
@@ -177,24 +171,29 @@ this.AccessFu = { // jshint ignore:line
     PointerAdapter.stop();
 
     Utils.win.removeEventListener('TabOpen', this);
     Utils.win.removeEventListener('TabClose', this);
     Utils.win.removeEventListener('TabSelect', this);
 
     Services.obs.removeObserver(this, 'remote-browser-shown');
     Services.obs.removeObserver(this, 'inprocess-browser-shown');
-    Services.obs.removeObserver(this, 'Accessibility:NextObject');
-    Services.obs.removeObserver(this, 'Accessibility:PreviousObject');
-    Services.obs.removeObserver(this, 'Accessibility:Focus');
-    Services.obs.removeObserver(this, 'Accessibility:ActivateObject');
-    Services.obs.removeObserver(this, 'Accessibility:LongPress');
-    Services.obs.removeObserver(this, 'Accessibility:ScrollForward');
-    Services.obs.removeObserver(this, 'Accessibility:ScrollBackward');
-    Services.obs.removeObserver(this, 'Accessibility:MoveByGranularity');
+
+    if (Utils.MozBuildApp === 'mobile/android') {
+      EventDispatcher.instance.unregisterListener(this, [
+        'Accessibility:ActivateObject',
+        'Accessibility:Focus',
+        'Accessibility:LongPress',
+        'Accessibility:MoveByGranularity',
+        'Accessibility:NextObject',
+        'Accessibility:PreviousObject',
+        'Accessibility:ScrollBackward',
+        'Accessibility:ScrollForward',
+      ]);
+    }
 
     delete this._quicknavModesPref;
     delete this._notifyOutputPref;
 
     if (this.doneCallback) {
       this.doneCallback();
       delete this.doneCallback;
     }
@@ -296,53 +295,57 @@ this.AccessFu = { // jshint ignore:line
 
   _handleMessageManager: function _handleMessageManager(aMessageManager) {
     if (this._enabled) {
       this._addMessageListeners(aMessageManager);
     }
     this._loadFrameScript(aMessageManager);
   },
 
-  observe: function observe(aSubject, aTopic, aData) {
-    switch (aTopic) {
+  onEvent: function (event, data, callback) {
+    switch (event) {
       case 'Accessibility:Settings':
-        this._systemPref = JSON.parse(aData).enabled;
+        this._systemPref = data.enabled;
         this._enableOrDisable();
         break;
       case 'Accessibility:NextObject':
-      case 'Accessibility:PreviousObject':
-      {
-        let rule = aData ?
-          aData.substr(0, 1).toUpperCase() + aData.substr(1).toLowerCase() :
+      case 'Accessibility:PreviousObject': {
+        let rule = data ?
+          data.rule.substr(0, 1).toUpperCase() + data.rule.substr(1).toLowerCase() :
           'Simple';
-        let method = aTopic.replace(/Accessibility:(\w+)Object/, 'move$1');
+        let method = event.replace(/Accessibility:(\w+)Object/, 'move$1');
         this.Input.moveCursor(method, rule, 'gesture');
         break;
       }
       case 'Accessibility:ActivateObject':
-        this.Input.activateCurrent(JSON.parse(aData));
+        this.Input.activateCurrent(data);
         break;
       case 'Accessibility:LongPress':
         this.Input.sendContextMenuMessage();
         break;
       case 'Accessibility:ScrollForward':
         this.Input.androidScroll('forward');
         break;
       case 'Accessibility:ScrollBackward':
         this.Input.androidScroll('backward');
         break;
       case 'Accessibility:Focus':
-        this._focused = JSON.parse(aData);
+        this._focused = data.gainFocus;
         if (this._focused) {
           this.autoMove({ forcePresent: true, noOpIfOnScreen: true });
         }
         break;
       case 'Accessibility:MoveByGranularity':
-        this.Input.moveByGranularity(JSON.parse(aData));
+        this.Input.moveByGranularity(data);
         break;
+    }
+  },
+
+  observe: function observe(aSubject, aTopic, aData) {
+    switch (aTopic) {
       case 'remote-browser-shown':
       case 'inprocess-browser-shown':
       {
         // Ignore notifications that aren't from a Browser
         let frameLoader = aSubject.QueryInterface(Ci.nsIFrameLoader);
         if (!frameLoader.ownerIsMozBrowserFrame) {
           return;
         }
@@ -577,35 +580,22 @@ var Output = {
         if (highlightBox) {
           highlightBox.classList.remove('show');
         }
         break;
       }
     }
   },
 
-  get androidBridge() {
-    delete this.androidBridge;
-    if (Utils.MozBuildApp === 'mobile/android') {
-      this.androidBridge = Services.androidBridge;
-    } else {
-      this.androidBridge = null;
-    }
-    return this.androidBridge;
-  },
-
   Android: function Android(aDetails, aBrowser) {
     const ANDROID_VIEW_TEXT_CHANGED = 0x10;
     const ANDROID_VIEW_TEXT_SELECTION_CHANGED = 0x2000;
 
-    if (!this.androidBridge) {
-      return;
-    }
-
     for (let androidEvent of aDetails) {
+      androidEvent.type = 'Accessibility:Event';
       if (androidEvent.bounds) {
         androidEvent.bounds = AccessFu.adjustContentBounds(
           androidEvent.bounds, aBrowser);
       }
 
       switch(androidEvent.eventType) {
         case ANDROID_VIEW_TEXT_CHANGED:
           androidEvent.brailleOutput = this.brailleState.adjustText(
@@ -615,19 +605,18 @@ var Output = {
           androidEvent.brailleOutput = this.brailleState.adjustSelection(
             androidEvent.brailleOutput);
           break;
         default:
           androidEvent.brailleOutput = this.brailleState.init(
             androidEvent.brailleOutput);
           break;
       }
-      let win = Utils.win;
-      let view = win && win.QueryInterface(Ci.nsIAndroidView);
-      view.dispatch('Accessibility:Event', androidEvent);
+
+      Utils.win.WindowEventDispatcher.sendRequest(androidEvent);
     }
   },
 
   Braille: function Braille(aDetails) {
     Logger.debug('Braille output: ' + aDetails.output);
   }
 };
 
@@ -813,19 +802,17 @@ var Input = {
             return;
           } else {
             target.blur();
           }
         }
 
         if (Utils.MozBuildApp == 'mobile/android') {
           // Return focus to native Android browser chrome.
-          let win = Utils.win;
-          let view = win && win.QueryInterface(Ci.nsIAndroidView);
-          view.dispatch('ToggleChrome:Focus');
+          Utils.win.WindowEventDispatcher.dispatch('ToggleChrome:Focus');
         }
         break;
       case aEvent.DOM_VK_RETURN:
         if (this.editState.editing) {
           return;
         }
         this.activateCurrent();
         break;
--- a/accessible/jsat/EventManager.jsm
+++ b/accessible/jsat/EventManager.jsm
@@ -111,17 +111,17 @@ this.EventManager.prototype = {
       {
         // the target could be an element, document or window
         let window = null;
         if (aEvent.target instanceof Ci.nsIDOMWindow)
           window = aEvent.target;
         else if (aEvent.target instanceof Ci.nsIDOMDocument)
           window = aEvent.target.defaultView;
         else if (aEvent.target instanceof Ci.nsIDOMElement)
-          window = aEvent.target.ownerDocument.defaultView;
+          window = aEvent.target.ownerGlobal;
         this.present(Presentation.viewportChanged(window));
         break;
       }
       }
     } catch (x) {
       Logger.logException(x, 'Error handling DOM event');
     }
   },
--- a/accessible/jsat/Presentation.jsm
+++ b/accessible/jsat/Presentation.jsm
@@ -310,17 +310,17 @@ AndroidPresenter.prototype.pivotChanged 
   };
 
 AndroidPresenter.prototype.actionInvoked =
   function AndroidPresenter_actionInvoked(aObject, aActionName) {
     let state = Utils.getState(aObject);
 
     // Checkable objects use TalkBack's text derived from the event state,
     // so we don't populate the text here.
-    let text = '';
+    let text = null;
     if (!state.contains(States.CHECKABLE)) {
       text = Utils.localize(UtteranceGenerator.genForAction(aObject,
         aActionName));
     }
 
     return {
       type: this.type,
       details: [{
--- a/accessible/jsat/Utils.jsm
+++ b/accessible/jsat/Utils.jsm
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* global Components, XPCOMUtils, Services, PluralForm, Logger, Rect, Utils,
           States, Relations, Roles, dump, Events, PivotContext, PrefCache */
-/* exported Utils, Logger, PivotContext, PrefCache, SettingCache */
+/* exported Utils, Logger, PivotContext, PrefCache */
 
 'use strict';
 
 const {classes: Cc, utils: Cu, interfaces: Ci} = Components;
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Services', // jshint ignore:line
   'resource://gre/modules/Services.jsm');
@@ -21,18 +21,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   'resource://gre/modules/accessibility/Constants.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Relations', // jshint ignore:line
   'resource://gre/modules/accessibility/Constants.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'States', // jshint ignore:line
   'resource://gre/modules/accessibility/Constants.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'PluralForm', // jshint ignore:line
   'resource://gre/modules/PluralForm.jsm');
 
-this.EXPORTED_SYMBOLS = ['Utils', 'Logger', 'PivotContext', 'PrefCache',  // jshint ignore:line
-                         'SettingCache'];
+this.EXPORTED_SYMBOLS = ['Utils', 'Logger', 'PivotContext', 'PrefCache']; // jshint ignore:line
 
 this.Utils = { // jshint ignore:line
   _buildAppMap: {
     '{3c2e2abc-06d4-11e1-ac3b-374f68613e61}': 'b2g',
     '{d1bfe7d9-c01e-4237-998b-7b5f960a4314}': 'graphene',
     '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}': 'browser',
     '{aa3c5121-dab2-40e2-81ca-7ea25febc110}': 'mobile/android',
     '{a23983c0-fd0e-11dc-95ff-0800200c9a66}': 'mobile/xul'
@@ -1069,46 +1068,8 @@ PrefCache.prototype = {
         Logger.logException(x);
       }
     }
   },
 
   QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver,
                                           Ci.nsISupportsWeakReference])
 };
-
-this.SettingCache = function SettingCache(aName, aCallback, aOptions = {}) { // jshint ignore:line
-  this.value = aOptions.defaultValue;
-  let runCallback = () => {
-    if (aCallback) {
-      aCallback(aName, this.value);
-      if (aOptions.callbackOnce) {
-        runCallback = () => {};
-      }
-    }
-  };
-
-  let settings = Utils.win.navigator.mozSettings;
-  if (!settings) {
-    if (aOptions.callbackNow) {
-      runCallback();
-    }
-    return;
-  }
-
-
-  let lock = settings.createLock();
-  let req = lock.get(aName);
-
-  req.addEventListener('success', () => {
-    this.value = req.result[aName] === undefined ?
-      aOptions.defaultValue : req.result[aName];
-    if (aOptions.callbackNow) {
-      runCallback();
-    }
-  });
-
-  settings.addObserver(aName,
-                       (evt) => {
-                         this.value = evt.settingValue;
-                         runCallback();
-                       });
-};
--- a/accessible/mac/mozAccessible.mm
+++ b/accessible/mac/mozAccessible.mm
@@ -8,16 +8,17 @@
 #import "MacUtils.h"
 #import "mozView.h"
 
 #include "Accessible-inl.h"
 #include "nsAccUtils.h"
 #include "nsIAccessibleRelation.h"
 #include "nsIAccessibleEditableText.h"
 #include "nsIPersistentProperties2.h"
+#include "DocAccessibleParent.h"
 #include "Relation.h"
 #include "Role.h"
 #include "RootAccessible.h"
 #include "TableAccessible.h"
 #include "TableCellAccessible.h"
 #include "mozilla/a11y/PDocAccessible.h"
 #include "OuterDocAccessible.h"
 
--- a/accessible/tests/browser/.eslintrc.js
+++ b/accessible/tests/browser/.eslintrc.js
@@ -1,13 +1,13 @@
 "use strict";
 
 module.exports = { // eslint-disable-line no-undef
   "extends": [
-    "../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ],
   // All globals made available in the test environment.
   "globals": {
     // Content scripts have global 'content' object
     "content": true,
 
     "add_task": true,
 
--- a/accessible/tests/browser/e10s/browser.ini
+++ b/accessible/tests/browser/e10s/browser.ini
@@ -1,10 +1,9 @@
 [DEFAULT]
-skip-if = (e10s && os == 'win') # Bug 1269369: Document loaded event does not fire in Windows
 support-files =
   events.js
   head.js
   doc_treeupdate_ariadialog.html
   doc_treeupdate_ariaowns.html
   doc_treeupdate_imagemap.html
   doc_treeupdate_removal.xhtml
   doc_treeupdate_visibility.html
@@ -13,16 +12,17 @@ support-files =
   !/accessible/tests/mochitest/*.js
   !/accessible/tests/mochitest/letters.gif
   !/accessible/tests/mochitest/moz.png
 
 # Caching tests
 [browser_caching_attributes.js]
 [browser_caching_description.js]
 [browser_caching_name.js]
+skip-if = e10s && os == 'win' && debug # Bug 1338034, leaks
 [browser_caching_relations.js]
 [browser_caching_states.js]
 [browser_caching_value.js]
 
 # Events tests
 [browser_events_caretmove.js]
 [browser_events_hide.js]
 [browser_events_show.js]
@@ -30,20 +30,20 @@ support-files =
 [browser_events_textchange.js]
 
 # Tree update tests
 [browser_treeupdate_ariadialog.js]
 [browser_treeupdate_ariaowns.js]
 [browser_treeupdate_canvas.js]
 [browser_treeupdate_cssoverflow.js]
 [browser_treeupdate_doc.js]
+skip-if = e10s && os == 'win' # Bug 1288839
 [browser_treeupdate_gencontent.js]
 [browser_treeupdate_hidden.js]
 [browser_treeupdate_imagemap.js]
-skip-if = (os == 'mac' && debug && e10s) # Bug 1318569
 [browser_treeupdate_list.js]
 [browser_treeupdate_list_editabledoc.js]
 [browser_treeupdate_listener.js]
 [browser_treeupdate_optgroup.js]
 [browser_treeupdate_removal.js]
 [browser_treeupdate_table.js]
 [browser_treeupdate_textleaf.js]
 [browser_treeupdate_visibility.js]
--- a/accessible/tests/browser/e10s/browser_caching_name.js
+++ b/accessible/tests/browser/e10s/browser_caching_name.js
@@ -387,17 +387,17 @@ function* testElmRule(browser, target, r
  * @param {[type]} expected     expected name value
  */
 function* testSubtreeRule(browser, target, rule, expected) {
   testName(target.acc, expected);
   let onEvent = waitForEvent(EVENT_REORDER, target.id);
   yield ContentTask.spawn(browser, target.id, id => {
     let elm = content.document.getElementById(id);
     while (elm.firstChild) {
-      elm.removeChild(elm.firstChild);
+      elm.firstChild.remove();
     }
   });
   yield updateAccessibleIfNeeded(onEvent, target);
 }
 
 /**
  * Iterate over a list of rules and test accessible names for each one of the
  * rules.
--- a/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js
@@ -112,18 +112,17 @@ function* testContainer1(browser, accDoc
       { GROUPING: [ ] } // ARIA owned, t1_group
     ]
   };
   testAccessibleTree(acc, tree);
 
   /* ================ Remove element ======================================== */
   onReorder = waitForEvent(EVENT_REORDER, id);
   yield ContentTask.spawn(browser, {}, () =>
-    content.document.getElementById('t1_span').parentNode.removeChild(
-      content.document.getElementById('t1_span')));
+    content.document.getElementById('t1_span').remove());
   yield onReorder;
 
   // subdiv should go away
   tree = {
     SECTION: [
       { CHECKBUTTON: [ ] }, // explicit, t1_checkbox
       { RADIOBUTTON: [ ] }, // explicit, t1_child3
       { PUSHBUTTON: [ ] }, // ARIA owned, t1_button
--- a/accessible/tests/browser/e10s/browser_treeupdate_doc.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_doc.js
@@ -152,17 +152,17 @@ addAccessibleTask(`
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Remove HTML from iframe document ===================== */
   reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
   yield ContentTask.spawn(browser, {}, () => {
     // Remove HTML element.
     let docNode = content.document.getElementById('iframe').contentDocument;
-    docNode.removeChild(docNode.firstChild);
+    docNode.firstChild.remove();
   });
   let event = yield reorderEventPromise;
 
   ok(event.accessible instanceof nsIAccessibleDocument,
     'Reorder should happen on the document');
   tree = {
     role: ROLE_DOCUMENT,
     children: [ ]
@@ -230,17 +230,17 @@ addAccessibleTask(`
   };
   testAccessibleTree(iframe, tree);
 
   reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
   yield ContentTask.spawn(browser, {}, () => {
     let docEl =
       content.document.getElementById('iframe').contentDocument.documentElement;
     // Remove aftermath of this test before next test starts.
-    docEl.removeChild(docEl.firstChild);
+    docEl.firstChild.remove();
   });
   // Make sure reorder event was fired and that the input was removed.
   yield reorderEventPromise;
   tree = {
     role: ROLE_DOCUMENT,
     children: [ ]
   };
   testAccessibleTree(iframe, tree);
--- a/accessible/tests/browser/e10s/browser_treeupdate_imagemap.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_imagemap.js
@@ -114,17 +114,17 @@ function* testContainer(browser) {
     } ]
   };
   testAccessibleTree(acc, tree);
 
   /* ================= Remove map =========================================== */
   onReorder = waitForEvent(EVENT_REORDER, id);
   yield ContentTask.spawn(browser, {}, () => {
     let mapNode = content.document.getElementById('map');
-    mapNode.parentNode.removeChild(mapNode);
+    mapNode.remove();
   });
   yield onReorder;
 
   tree = {
     SECTION: [
       { GRAPHIC: [ ] }
     ]
   };
@@ -165,12 +165,27 @@ function* testContainer(browser) {
   yield onReorder;
 
   tree = {
     SECTION: [ ]
   };
   testAccessibleTree(acc, tree);
 }
 
+function* waitForImageMap(browser, accDoc) {
+  const id = 'imgmap';
+  const acc = findAccessibleChildByID(accDoc, id);
+  if (acc.firstChild) {
+    return;
+  }
+
+  const onReorder = waitForEvent(EVENT_REORDER, id);
+  // Wave over image map
+  yield BrowserTestUtils.synthesizeMouse(`#${id}`, 10, 10,
+                                         { type: 'mousemove' }, browser);
+  yield onReorder;
+}
+
 addAccessibleTask('doc_treeupdate_imagemap.html', function*(browser, accDoc) {
+  yield waitForImageMap(browser, accDoc);
   yield testImageMap(browser, accDoc);
   yield testContainer(browser);
 });
--- a/accessible/tests/browser/e10s/browser_treeupdate_listener.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_listener.js
@@ -21,23 +21,9 @@ addAccessibleTask('<span id="parent"><sp
       content.window.dummyListener = () => {};
       content.document.getElementById('parent').addEventListener(
         'click', content.window.dummyListener);
     });
     yield onReorder;
 
     let tree = { TEXT: [] };
     testAccessibleTree(findAccessibleChildByID(accDoc, 'parent'), tree);
-
-    onReorder = waitForEvent(EVENT_REORDER, 'body');
-    // Remove an event listener from parent.
-    yield ContentTask.spawn(browser, {}, () => {
-      content.document.getElementById('parent').removeEventListener(
-        'click', content.window.dummyListener);
-      delete content.window.dummyListener;
-    });
-    yield onReorder;
-
-    is(findAccessibleChildByID(accDoc, 'parent'), null,
-      'Check that parent is not accessible.');
-    is(findAccessibleChildByID(accDoc, 'child'), null,
-      'Check that child is not accessible.');
   });
--- a/accessible/tests/browser/e10s/browser_treeupdate_optgroup.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_optgroup.js
@@ -51,17 +51,17 @@ addAccessibleTask('<select id="select"><
   };
   testAccessibleTree(select, tree);
   ok(!isDefunct(option1Node), 'option shouldn\'t be defunct');
 
   onEvent = waitForEvent(EVENT_REORDER, 'select');
   // Remove grouping from combobox
   yield ContentTask.spawn(browser, {}, () => {
     let contentSelect = content.document.getElementById('select');
-    contentSelect.removeChild(contentSelect.firstChild);
+    contentSelect.firstChild.remove();
   });
   yield onEvent;
 
   tree = {
     COMBOBOX: [ {
       COMBOBOX_LIST: [
         { COMBOBOX_OPTION: [] },
         { COMBOBOX_OPTION: [] }
--- a/accessible/tests/crashtests/448064.xhtml
+++ b/accessible/tests/crashtests/448064.xhtml
@@ -27,40 +27,37 @@ function dumpAccessibleNode(aNode, level
 		msg += " noName ";
 	}
 	
 	dump(msg + '\n');
 }
 
 
 function dumpAccessibleTree(aNode, level) {
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 	level = level || 0;
 
 	dumpAccessibleNode(aNode, level);
 	try {	
 		var child = aNode.firstChild;
 		while (child) {
 			dumpAccessibleTree(child, level + 1);
 			child = child.nextSibling;
 		}
 	} catch (e) {
 		dump("Error visiting child nodes: " + e + '\n');
 	}
 }
 
 function A(o) { 
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var acc = Components.classes['@mozilla.org/accessibilityService;1']
-                         .getService(Components.interfaces.nsIAccessibilityService);
+  var acc = SpecialPowers.Cc['@mozilla.org/accessibilityService;1']
+                         .getService(SpecialPowers.Ci.nsIAccessibilityService);
   return acc.getAccessibleFor(o);
 }
 
 function beginAccessible() {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   dumpAccessibleTree(A(document),0);
 }
 setTimeout(beginAccessible, 100);
 
 
 setTimeout(doe, 200);
 function doe() {
    document.getElementById('mw_a').appendChild(document.getElementById('mw_b'));
--- a/accessible/tests/mochitest/attributes.js
+++ b/accessible/tests/mochitest/attributes.js
@@ -28,17 +28,17 @@ function testAbsentAttrs(aAccOrElmOrID, 
 }
 
 /**
  * Test CSS based object attributes.
  */
 function testCSSAttrs(aID)
 {
   var node = document.getElementById(aID);
-  var computedStyle = document.defaultView.getComputedStyle(node, "");
+  var computedStyle = document.defaultView.getComputedStyle(node);
 
   var attrs = {
     "display": computedStyle.display,
     "text-align": computedStyle.textAlign,
     "text-indent": computedStyle.textIndent,
     "margin-left": computedStyle.marginLeft,
     "margin-right": computedStyle.marginRight,
     "margin-top": computedStyle.marginTop,
@@ -263,18 +263,18 @@ function fontFamily(aComputedStyle)
  * @param aID          [in] identifier of accessible
  * @param aFontSize    [in] font size
  * @param aFontWeight  [in, optional] kBoldFontWeight or kNormalFontWeight,
  *                      default value is kNormalFontWeight
  */
 function buildDefaultTextAttrs(aID, aFontSize, aFontWeight, aFontFamily)
 {
   var elm = getNode(aID);
-  var computedStyle = document.defaultView.getComputedStyle(elm, "");
-  var bgColor = computedStyle.backgroundColor == "transparent" ?
+  var computedStyle = document.defaultView.getComputedStyle(elm);
+  var bgColor = computedStyle.backgroundColor == "rgba(0, 0, 0, 0)" ?
     "rgb(255, 255, 255)" : computedStyle.backgroundColor;
 
   var defAttrs = {
     "font-style": computedStyle.fontStyle,
     "font-size": aFontSize,
     "background-color": bgColor,
     "font-weight": aFontWeight ? aFontWeight : kNormalFontWeight,
     "color": computedStyle.color,
--- a/accessible/tests/mochitest/attributes/test_obj_css.html
+++ b/accessible/tests/mochitest/attributes/test_obj_css.html
@@ -23,17 +23,17 @@
       this.accessible = getAccessible(aID);
 
       this.eventSeq = [
         new invokerChecker(EVENT_HIDE, this.accessible)
       ];
 
       this.invoke = function removeElm_invoke()
       {
-        this.node.parentNode.removeChild(this.node);
+        this.node.remove();
       }
 
       this.check = function removeElm_check()
       {
         testAbsentCSSAttrs(this.accessible);
       }
 
       this.getID = function removeElm_getID()
--- a/accessible/tests/mochitest/attributes/test_obj_group.html
+++ b/accessible/tests/mochitest/attributes/test_obj_group.html
@@ -197,17 +197,17 @@
       testGroupAttrs("t1_li2", 2, 3);
       testGroupAttrs("t1_li3", 3, 3);
 
       // Test that group position information updates after deleting node.
       testGroupAttrs("tree4_ti1", 1, 2, 1);
       testGroupAttrs("tree4_ti2", 2, 2, 1);
       var tree4element = document.getElementById("tree4_ti1");
       var tree4acc = getAccessible("tree4");
-      tree4element.parentNode.removeChild(tree4element);
+      tree4element.remove();
       waitForEvent(EVENT_REORDER, tree4acc, function() {
         testGroupAttrs("tree4_ti2", 1, 1, 1);
         SimpleTest.finish();
       });
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
--- a/accessible/tests/mochitest/events.js
+++ b/accessible/tests/mochitest/events.js
@@ -107,17 +107,17 @@ function waitForEvent(aEventType, aTarge
 /**
  * Generate mouse move over image map what creates image map accessible (async).
  * See waitForImageMap() function.
  */
 function waveOverImageMap(aImageMapID)
 {
   var imageMapNode = getNode(aImageMapID);
   synthesizeMouse(imageMapNode, 10, 10, { type: "mousemove" },
-                  imageMapNode.ownerDocument.defaultView);
+                  imageMapNode.ownerGlobal);
 }
 
 /**
  * Call the given function when the tree of the given image map is built.
  */
 function waitForImageMap(aImageMapID, aTestFunc)
 {
   waveOverImageMap(aImageMapID);
@@ -1592,17 +1592,17 @@ function moveCaretToDOMPoint(aID, aDOMPo
   this.focus = aFocusTargetID ? getAccessible(aFocusTargetID) : null;
   this.focusNode = this.focus ? this.focus.DOMNode : null;
 
   this.invoke = function moveCaretToDOMPoint_invoke()
   {
     if (this.focusNode)
       this.focusNode.focus();
 
-    var selection = this.DOMPointNode.ownerDocument.defaultView.getSelection();
+    var selection = this.DOMPointNode.ownerGlobal.getSelection();
     var selRange = selection.getRangeAt(0);
     selRange.setStart(this.DOMPointNode, aDOMPointOffset);
     selRange.collapse(true);
 
     selection.removeRange(selRange);
     selection.addRange(selRange);
   }
 
@@ -1758,23 +1758,37 @@ function nofocusChecker(aID)
   this.__proto__ = new focusChecker(aID);
   this.unexpected = true;
 }
 
 /**
  * Text inserted/removed events checker.
  * @param aFromUser  [in, optional] kNotFromUserInput or kFromUserInput
  */
-function textChangeChecker(aID, aStart, aEnd, aTextOrFunc, aIsInserted, aFromUser)
+function textChangeChecker(aID, aStart, aEnd, aTextOrFunc, aIsInserted, aFromUser, aAsync)
 {
   this.target = getNode(aID);
   this.type = aIsInserted ? EVENT_TEXT_INSERTED : EVENT_TEXT_REMOVED;
   this.startOffset = aStart;
   this.endOffset = aEnd;
   this.textOrFunc = aTextOrFunc;
+  this.async = aAsync;
+
+  this.match = function stextChangeChecker_match(aEvent)
+  {
+    if (!(aEvent instanceof nsIAccessibleTextChangeEvent) ||
+        aEvent.accessible !== getAccessible(this.target)) {
+      return false;
+    }
+
+    let tcEvent = aEvent.QueryInterface(nsIAccessibleTextChangeEvent);
+    let modifiedText = (typeof this.textOrFunc === "function") ?
+      this.textOrFunc() : this.textOrFunc;
+    return modifiedText === tcEvent.modifiedText;
+  };
 
   this.check = function textChangeChecker_check(aEvent)
   {
     aEvent.QueryInterface(nsIAccessibleTextChangeEvent);
 
     var modifiedText = (typeof this.textOrFunc == "function") ?
       this.textOrFunc() : this.textOrFunc;
     var modifiedTextLen =
--- a/accessible/tests/mochitest/events/a11y.ini
+++ b/accessible/tests/mochitest/events/a11y.ini
@@ -7,16 +7,18 @@ support-files =
   !/accessible/tests/mochitest/letters.gif
 
 [test_aria_alert.html]
 [test_aria_menu.html]
 [test_aria_objattr.html]
 [test_aria_owns.html]
 [test_aria_statechange.html]
 [test_attrs.html]
+[test_bug1322593.html]
+[test_bug1322593-2.html]
 [test_caretmove.html]
 [test_caretmove.xul]
 [test_coalescence.html]
 [test_contextmenu.html]
 [test_descrchange.html]
 [test_docload.html]
 [test_docload.xul]
 skip-if = buildapp == 'mulet'
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/events/test_bug1322593-2.html
@@ -0,0 +1,83 @@
+<html>
+
+<head>
+  <title>Accessible mutation events testing</title>
+
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+    function changeMultipleElements()
+    {
+      this.node1 = getNode("span1");
+      this.node2 = getNode("span2");
+
+      this.eventSeq = [
+        new textChangeChecker("container", 0, 5, "hello", false, undefined, true),
+        new textChangeChecker("container", 6, 11, "world", false, undefined, true),
+        new orderChecker(),
+        new textChangeChecker("container", 0, 1, "a", true, undefined, true),
+        new textChangeChecker("container", 7, 8, "b", true, undefined, true)
+      ];
+
+      this.invoke = function changeMultipleElements_invoke()
+      {
+        this.node1.textContent = "a";
+        this.node2.textContent = "b";
+      }
+
+      this.getID = function changeMultipleElements_invoke_getID()
+      {
+        return "Change the text content of multiple sibling divs";
+      }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Do tests
+//    gA11yEventDumpToConsole = true; // debugging
+
+    var gQueue = null;
+    function doTests()
+    {
+      gQueue = new eventQueue();
+
+      gQueue.push(new changeMultipleElements());
+
+      gQueue.invoke(); // Will call SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTests);
+  </script>
+</head>
+
+<body>
+
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=1322593"
+     title="missing text change events when multiple elements updated at once">
+    Mozilla Bug 1322593
+  </a>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <div id="container">
+  <span id="span1">hello</span>
+  <span>your</span>
+  <span id="span2">world</span>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/events/test_bug1322593.html
@@ -0,0 +1,80 @@
+<html>
+
+<head>
+  <title>Accessible mutation events testing</title>
+
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+    function changeMultipleElements()
+    {
+      this.node1 = getNode("div1");
+      this.node2 = getNode("div2");
+
+      this.eventSeq = [
+        new textChangeChecker("div1", 0, 5, "hello", false, undefined, true),
+        new textChangeChecker("div2", 0, 5, "world", false, undefined, true),
+        new orderChecker(),
+        new textChangeChecker("div1", 0, 1, "a", true, undefined, true),
+        new textChangeChecker("div2", 0, 1, "b", true, undefined, true)
+      ];
+
+      this.invoke = function changeMultipleElements_invoke()
+      {
+        this.node1.textContent = "a";
+        this.node2.textContent = "b";
+      }
+
+      this.getID = function changeMultipleElements_invoke_getID()
+      {
+        return "Change the text content of multiple sibling divs";
+      }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Do tests
+//    gA11yEventDumpToConsole = true; // debugging
+
+    var gQueue = null;
+    function doTests()
+    {
+      gQueue = new eventQueue();
+
+      gQueue.push(new changeMultipleElements());
+
+      gQueue.invoke(); // Will call SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTests);
+  </script>
+</head>
+
+<body>
+
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=1322593"
+     title="missing text change events when multiple elements updated at once">
+    Mozilla Bug 1322593
+  </a>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <div id="div1">hello</div>
+  <div id="div2">world</div>
+</body>
+</html>
--- a/accessible/tests/mochitest/events/test_coalescence.html
+++ b/accessible/tests/mochitest/events/test_coalescence.html
@@ -69,17 +69,17 @@
       }
 
       // Implementation details
 
       this.invokeAction = function coalescenceBase_invokeAction(aNode, aAction)
       {
         switch (aAction) {
           case kRemoveElm:
-            aNode.parentNode.removeChild(aNode);
+            aNode.remove();
             break;
 
           case kHideElm:
             aNode.style.display = "none";
             break;
 
           case kAddElm:
             if (aNode == this.parentNode)
@@ -323,18 +323,18 @@
         new invokerChecker(EVENT_REORDER, getNode(aParentId).parentNode),
         new unexpectedInvokerChecker(EVENT_HIDE, getAccessible(aChild1Id)),
         new unexpectedInvokerChecker(EVENT_HIDE, getAccessible(aChild2Id)),
         new unexpectedInvokerChecker(EVENT_REORDER, getAccessible(aParentId))
       ];
 
       this.invoke = function removeGrandChildrenNHideParent_invoke()
       {
-        this.child1.parentNode.removeChild(this.child1);
-        this.child2.parentNode.removeChild(this.child2);
+        this.child1.remove();
+        this.child2.remove();
         this.parent.hidden = true;
       }
 
       this.getID = function removeGrandChildrenNHideParent_getID() {
         return "remove grand children of different parents and then hide their grand parent";
       }
     }
 
--- a/accessible/tests/mochitest/events/test_focus_autocomplete.xul
+++ b/accessible/tests/mochitest/events/test_focus_autocomplete.xul
@@ -156,17 +156,17 @@
     function focusOnMouseOver(aIDFunc, aIDFuncArg)
     {
       this.eventSeq = [ new focusChecker(aIDFunc, aIDFuncArg) ];
 
       this.invoke = function focusOnMouseOver_invoke()
       {
         this.id = aIDFunc.call(null, aIDFuncArg);
         this.node = getNode(this.id);
-        this.window = this.node.ownerDocument.defaultView;
+        this.window = this.node.ownerGlobal;
 
         if (this.node.localName == "tree") {
           var tree = getAccessible(this.node);
           var accessible = getAccessible(this.id);
           if (tree != accessible) {
             var itemX = {}, itemY = {}, treeX = {}, treeY = {};
             accessible.getBounds(itemX, itemY, {}, {});
             tree.getBounds(treeX, treeY, {}, {});
@@ -214,17 +214,17 @@
                            aFocusTargetFunc, aFocusTargetFuncArg)
     {
       this.eventSeq = [ new focusChecker(aFocusTargetFunc, aFocusTargetFuncArg) ];
 
       this.invoke = function selectByClick_invoke()
       {
         var id = aIDFunc.call(null, aIDFuncArg);
         var node = getNode(id);
-        var targetWindow = node.ownerDocument.defaultView;
+        var targetWindow = node.ownerGlobal;
 
         var x = 0, y = 0;
         if (node.localName == "tree") {
           var tree = getAccessible(node);
           var accessible = getAccessible(id);
           if (tree != accessible) {
             var itemX = {}, itemY = {}, treeX = {}, treeY = {};
             accessible.getBounds(itemX, itemY, {}, {});
--- a/accessible/tests/mochitest/events/test_focus_name.html
+++ b/accessible/tests/mochitest/events/test_focus_name.html
@@ -68,30 +68,30 @@
     var gTooltipElm = null;
 
     function doTests()
     {
       gButtonElm = getNode("button");
       gTextboxElm = getNode("textbox");
       gTooltipElm = getNode("tooltip");
 
-      gButtonElm.addEventListener("focus", gFocusHandler, false);
-      gButtonElm.addEventListener("blur", gBlurHandler, false);
-      gTextboxElm.addEventListener("focus", gFocusHandler, false);
-      gTextboxElm.addEventListener("blur", gBlurHandler, false);
+      gButtonElm.addEventListener("focus", gFocusHandler);
+      gButtonElm.addEventListener("blur", gBlurHandler);
+      gTextboxElm.addEventListener("focus", gFocusHandler);
+      gTextboxElm.addEventListener("blur", gBlurHandler);
 
       // The aria-describedby is changed on DOM focus. Accessible description
       // should be updated when a11y focus is fired.
       gQueue = new eventQueue(nsIAccessibleEvent.EVENT_FOCUS);
       gQueue.onFinish = function()
       {
-        gButtonElm.removeEventListener("focus", gFocusHandler, false);
-        gButtonElm.removeEventListener("blur", gBlurHandler, false);
-        gTextboxElm.removeEventListener("focus", gFocusHandler, false);
-        gTextboxElm.removeEventListener("blur", gBlurHandler, false);
+        gButtonElm.removeEventListener("focus", gFocusHandler);
+        gButtonElm.removeEventListener("blur", gBlurHandler);
+        gTextboxElm.removeEventListener("focus", gFocusHandler);
+        gTextboxElm.removeEventListener("blur", gBlurHandler);
       }
 
       var descr = "It's a tooltip";
       gQueue.push(new synthFocus("button", new actionChecker("button", descr)));
       gQueue.push(new synthTab("textbox", new actionChecker("textbox", descr)));
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
--- a/accessible/tests/mochitest/events/test_mutation.html
+++ b/accessible/tests/mochitest/events/test_mutation.html
@@ -197,17 +197,17 @@
       var eventTypes = aEventTypes || kHideEvents;
       var doNotExpectEvents = (aEventTypes == kNoEvents);
 
       this.__proto__ = new mutateA11yTree(aNodeOrID, eventTypes,
                                           doNotExpectEvents);
 
       this.invoke = function removeFromDOM_invoke()
       {
-        this.DOMNode.parentNode.removeChild(this.DOMNode);
+        this.DOMNode.remove();
       }
 
       this.getID = function removeFromDOM_getID()
       {
         return prettyName(aNodeOrID) + " remove from DOM.";
       }
 
       if (aTargetsFunc && (eventTypes & kHideEvent))
@@ -382,22 +382,22 @@
       this.txt = null;
       this.eventSeq = [
         new invokerChecker(EVENT_HIDE, function() { return this.txt; }.bind(this))
       ];
 
       this.invoke = function hideNDestroyDoc_invoke()
       {
         this.txt = getAccessible('c5').firstChild.firstChild;
-        this.txt.DOMNode.parentNode.removeChild(this.txt.DOMNode);
+        this.txt.DOMNode.remove();
       }
 
       this.check = function hideNDestroyDoc_check()
       {
-        getNode('c5').parentNode.removeChild(getNode('c5'));
+        getNode('c5').remove();
       }
 
       this.getID = function hideNDestroyDoc_getID()
       {
         return "remove text node and destroy a document on hide event";
       }
     }
 
@@ -409,23 +409,23 @@
       ];
 
       this.invoke = function hideHideNDestroyDoc_invoke()
       {
         var doc = getAccessible('c6').firstChild;
         var l1 = doc.firstChild;
         this.target = l1.firstChild;
         var l2 = doc.lastChild;
-        l1.DOMNode.removeChild(l1.DOMNode.firstChild);
-        l2.DOMNode.removeChild(l2.DOMNode.firstChild);
+        l1.DOMNode.firstChild.remove();
+        l2.DOMNode.firstChild.remove();
       }
 
       this.check = function hideHideNDestroyDoc_check()
       {
-        getNode('c6').parentNode.removeChild(getNode('c6'));
+        getNode('c6').remove();
       }
 
       this.getID = function hideHideNDestroyDoc_getID()
       {
         return "remove text nodes (2 events in the queue) and destroy a document on first hide event";
       }
     }
 
--- a/accessible/tests/mochitest/events/test_text.html
+++ b/accessible/tests/mochitest/events/test_text.html
@@ -46,17 +46,17 @@
      */
     function removeChildSpan(aID)
     {
       this.__proto__ = new textRemoveInvoker(aID, 0, 5, "33322");
 
       this.invoke = function removeChildSpan_invoke()
       {
         // remove HTML span, a first child of the node
-        this.DOMNode.removeChild(this.DOMNode.firstChild);
+        this.DOMNode.firstChild.remove();
       }
 
       this.getID = function removeChildSpan_getID()
       {
         return "Remove inaccessible span containing accessible nodes" + prettyName(aID);
       }
     }
 
@@ -157,17 +157,17 @@
 
       this.invoke = function removeChildren_invoke()
       {
         if (aLastToFirst) {
           while (this.DOMNode.firstChild)
             this.DOMNode.removeChild(this.DOMNode.lastChild);
         } else {
           while (this.DOMNode.firstChild)
-            this.DOMNode.removeChild(this.DOMNode.firstChild);
+            this.DOMNode.firstChild.remove();
         }
       }
 
       this.getID = function removeChildren_getID()
       {
         return "remove children of " + prettyName(aID) +
           (aLastToFirst ? " from last to first" : " from first to last");
       }
--- a/accessible/tests/mochitest/grid.js
+++ b/accessible/tests/mochitest/grid.js
@@ -59,18 +59,18 @@ function grid(aTableIdentifier)
           return cell;
       }
     }
     return null;
   }
 
   this.initGrid = function initGrid()
   {
-    this.table.addEventListener("keypress", this, false);
-    this.table.addEventListener("click", this, false);
+    this.table.addEventListener("keypress", this);
+    this.table.addEventListener("click", this);
   }
 
   this.handleEvent = function handleEvent(aEvent)
   {
     if (aEvent instanceof nsIDOMKeyEvent)
       this.handleKeyEvent(aEvent);
     else
       this.handleClickEvent(aEvent);
--- a/accessible/tests/mochitest/jsat/jsatcommon.js
+++ b/accessible/tests/mochitest/jsat/jsatcommon.js
@@ -144,18 +144,17 @@ var AccessFuTest = {
     AccessFu.attach(getMainChromeWindow(window));
 
     AccessFu.readyCallback = function readyCallback() {
       // Enable logging to the console service.
       Logger.test = true;
       Logger.logLevel = Logger.DEBUG;
     };
 
-    var prefs = [['accessibility.accessfu.notify_output', 1],
-      ['dom.mozSettings.enabled', true]];
+    var prefs = [['accessibility.accessfu.notify_output', 1]];
     prefs.push.apply(prefs, aAdditionalPrefs);
 
     this.originalDwellThreshold = GestureSettings.dwellThreshold;
     this.originalSwipeMaxDuration = GestureSettings.swipeMaxDuration;
     this.originalMaxGestureResolveTimeout =
       GestureSettings.maxGestureResolveTimeout;
     // https://bugzilla.mozilla.org/show_bug.cgi?id=1001945 - sometimes
     // SimpleTest.executeSoon timeout is bigger than the timer settings in
--- a/accessible/tests/mochitest/jsat/output.js
+++ b/accessible/tests/mochitest/jsat/output.js
@@ -55,16 +55,17 @@ function testContextOutput(expected, aAc
 function testObjectOutput(aAccOrElmOrID, aGenerator) {
   var accessible = getAccessible(aAccOrElmOrID);
   if (!accessible.name || !accessible.name.trim()) {
     return;
   }
   var context = new PivotContext(accessible);
   var output = aGenerator.genForObject(accessible, context);
   var outputOrder;
+  // eslint-disable-next-line mozilla/use-default-preference-values
   try {
     outputOrder = SpecialPowers.getIntPref(PREF_UTTERANCE_ORDER);
   } catch (ex) {
     // PREF_UTTERANCE_ORDER not set.
     outputOrder = 0;
   }
   var expectedNameIndex = outputOrder === 0 ? output.length - 1 : 0;
   var nameIndex = output.indexOf(accessible.name);
--- a/accessible/tests/mochitest/jsat/test_content_text.html
+++ b/accessible/tests/mochitest/jsat/test_content_text.html
@@ -63,26 +63,26 @@
              { android_todo: true /* Bug 980512 */})],
 
           // Editable text tests.
           [ContentMessages.focusSelector('textarea'),
            new ExpectedAnnouncement('editing'),
            new ExpectedEditState({
             editing: true,
             multiline: true,
-            atStart: false,
-            atEnd: true
+            atStart: true,
+            atEnd: false
            }),
            new ExpectedCursorChange(
             ['Please refrain from Mayoneggs during this salmonella scare.',
              {string: 'textarea'}]),
-           new ExpectedTextSelectionChanged(59, 59)
+           new ExpectedTextSelectionChanged(0, 0)
           ],
           [ContentMessages.activateCurrent(10),
-           new ExpectedTextCaretChanged(10, 59),
+           new ExpectedTextCaretChanged(0, 10),
            new ExpectedEditState({ editing: true,
              multiline: true,
              atStart: false,
              atEnd: false }),
            new ExpectedTextSelectionChanged(10, 10)],
           [ContentMessages.activateCurrent(20),
            new ExpectedTextCaretChanged(10, 20),
            new ExpectedTextSelectionChanged(20, 20)
@@ -131,17 +131,16 @@
            new ExpectedClickAction(),
            new ExpectedAnnouncement('editing'),
            new ExpectedEditState({
             editing: true,
             multiline: false,
             atStart: true,
             atEnd: true
            }, { focused: 'input[type=text]' }),
-           new ExpectedTextSelectionChanged(0, 0),
            new ExpectedTextSelectionChanged(0, 0)
            ],
           [ContentMessages.simpleMovePrevious,
            new ExpectedCursorChange(
             ['So we don\'t get dessert?', {string: 'label'}]),
            new ExpectedAnnouncement('navigating'),
            new ExpectedEditState({
             editing: false,
--- a/accessible/tests/mochitest/layout.js
+++ b/accessible/tests/mochitest/layout.js
@@ -230,17 +230,17 @@ function getBoundsForDOMElm(aID)
   else {
     var rect = elm.getBoundingClientRect();
     x = rect.left;
     y = rect.top;
     width = rect.width;
     height = rect.height;
   }
 
-  var elmWindow = elm.ownerDocument.defaultView;
+  var elmWindow = elm.ownerGlobal;
   return CSSToDevicePixels(elmWindow,
                            x + elmWindow.mozInnerScreenX,
                            y + elmWindow.mozInnerScreenY,
                            width,
                            height);
 }
 
 function CSSToDevicePixels(aWindow, aX, aY, aWidth, aHeight)
--- a/accessible/tests/mochitest/name/markup.js
+++ b/accessible/tests/mochitest/name/markup.js
@@ -311,17 +311,17 @@ function testNameForSubtreeRule(aElm, aR
 
   if (gDumpToConsole) {
     dump("\nProcessed from subtree rule. Wait for reorder event on " +
          prettyName(aElm) + "\n");
   }
   waitForEvent(EVENT_REORDER, aElm, gTestIterator.iterateNext, gTestIterator);
 
   while (aElm.firstChild)
-    aElm.removeChild(aElm.firstChild);
+    aElm.firstChild.remove();
 }
 
 /**
  * Return array of 'rule' elements. Used in conjunction with
  * getRuleElmsFromRulesetElm() function.
  */
 function getRuleElmsByRulesetId(aRulesetId)
 {
--- a/accessible/tests/mochitest/pivot.js
+++ b/accessible/tests/mochitest/pivot.js
@@ -471,17 +471,17 @@ function removeVCPositionChecker(aDocAcc
  *                    set to it.
  */
 function removeVCPositionInvoker(aDocAcc, aPosNode)
 {
   this.accessible = getAccessible(aPosNode);
   this.invoke = function removeVCPositionInvoker_invoke()
   {
     aDocAcc.virtualCursor.position = this.accessible;
-    aPosNode.parentNode.removeChild(aPosNode);
+    aPosNode.remove();
   };
 
   this.getID = function removeVCPositionInvoker_getID()
   {
     return "Bring virtual cursor to accessible, and remove its DOM node.";
   };
 
   this.eventSeq = [
@@ -518,17 +518,17 @@ function removeVCRootChecker(aPivot)
  *                       pivot. Should have more than one child.
  */
 function removeVCRootInvoker(aRootNode)
 {
   this.pivot = gAccService.createAccessiblePivot(getAccessible(aRootNode));
   this.invoke = function removeVCRootInvoker_invoke()
   {
     this.pivot.position = this.pivot.root.firstChild;
-    aRootNode.parentNode.removeChild(aRootNode);
+    aRootNode.remove();
   };
 
   this.getID = function removeVCRootInvoker_getID()
   {
     return "Remove root of pivot from tree.";
   };
 
   this.eventSeq = [
--- a/accessible/tests/mochitest/states/test_aria.html
+++ b/accessible/tests/mochitest/states/test_aria.html
@@ -174,16 +174,19 @@
                  STATE_READONLY, 0);
       testStates("aria_treegrid_readonly_rowheader_inherited", STATE_READONLY, 0,
                  0, EXT_STATE_EDITABLE);
       testStates("aria_treegrid_readonly_cell_editable", 0, EXT_STATE_EDITABLE,
                  STATE_READONLY, 0);
       testStates("aria_treegrid_readonly_cell_inherited", STATE_READONLY, 0,
                  0, EXT_STATE_EDITABLE);
 
+      // aria-readonly on directory
+      testStates("aria_directory", STATE_READONLY);
+
       // aria-selectable
       testStates("aria_selectable_listitem", STATE_SELECTABLE | STATE_SELECTED);
 
       // active state caused by aria-activedescendant
       testStates("as_item1", 0, EXT_STATE_ACTIVE);
       testStates("as_item2", 0, 0, 0, EXT_STATE_ACTIVE);
 
       // universal ARIA properties inherited from file input control
@@ -620,10 +623,13 @@
     <div role="treeitem">G</div>
     <div role="treeitem">g</div>
   </div>
   <div id="aria_treegrid_disabled" role="treegrid" aria-disabled="true">
     <div role="row"><div role="gridcell">H</div></div>
     <div role="row"><div role="gridcell">h</div></div>
   </div>
 
+  <!-- Test that directory is readonly -->
+  <div id="aria_directory" role="directory"></div>
+
 </body>
 </html>
--- a/accessible/tests/mochitest/states/test_inputs.html
+++ b/accessible/tests/mochitest/states/test_inputs.html
@@ -102,16 +102,17 @@
       testStates(valid[i] + "2", 0, 0, STATE_INVALID);
     }
 
     ////////////////////////////////////////////////////////////////////////////
     // 'invalid' state
     // (per spec, min/maxlength validity is affected by interactive edits)
     var mininp = document.getElementById("minlength");
     mininp.focus();
+    mininp.setSelectionRange(mininp.value.length, mininp.value.length);
     synthesizeKey("VK_BACK_SPACE", {});
     ok(!mininp.validity.valid,
        "input should be invalid after interactive edits");
     testStates(mininp, STATE_INVALID);
     // inputs currently cannot be made longer than maxlength interactively,
     // so we're not testing that case.
 
     ////////////////////////////////////////////////////////////////////////////
--- a/accessible/tests/mochitest/test_bug420863.html
+++ b/accessible/tests/mochitest/test_bug420863.html
@@ -41,17 +41,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       var td3Node = getNode("td3");
 
       // register 'click' event handler
       gClickHandler = {
         handleEvent: function handleEvent(aEvent)
         {
         }
       };
-      td3Node.addEventListener("click", gClickHandler, false);
+      td3Node.addEventListener("click", gClickHandler);
 
       // check actions
       var actionsArray = [
         {
           ID: "td2", // "onclick" attribute
           actionName: "click",
           actionIndex: 0,
           events: CLICK_EVENTS
@@ -59,17 +59,17 @@ https://bugzilla.mozilla.org/show_bug.cg
         {
           ID: td3Node,
           actionName: "click",
           actionIndex: 0,
           events: CLICK_EVENTS,
           checkOnClickEvent: function check(aEvent)
           {
             // unregister click event handler
-            this.ID.removeEventListener("click", gClickHandler, false);
+            this.ID.removeEventListener("click", gClickHandler);
 
             // check actions
             is(getAccessible(this.ID).actionCount, 0,
                "td3 shouldn't have actions");
           }
         }
       ];
 
--- a/accessible/tests/mochitest/textattrs/test_general.html
+++ b/accessible/tests/mochitest/textattrs/test_general.html
@@ -48,17 +48,17 @@
 
       attrs = {};
       testTextAttrs(ID, 0, attrs, defAttrs, 0, 7);
 
       attrs = { "font-weight": kBoldFontWeight };
       testTextAttrs(ID, 7, attrs, defAttrs, 7, 12);
 
       var tempElem = getNode(ID).firstChild.nextSibling.firstChild.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = {"font-style": gComputedStyle.fontStyle,
                "font-weight": kBoldFontWeight };
       testTextAttrs(ID, 13, attrs, defAttrs, 12, 19);
 
       attrs = { "font-weight": kBoldFontWeight };
       testTextAttrs(ID, 20, attrs, defAttrs, 19, 23);
 
       attrs = {};
@@ -66,66 +66,66 @@
 
       //////////////////////////////////////////////////////////////////////////
       // area3
       ID = "area3";
       defAttrs = buildDefaultTextAttrs(ID, "12pt");
       testDefaultTextAttrs(ID, defAttrs);
 
       tempElem = getNode(ID).firstChild.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = {"color": gComputedStyle.color};
       testTextAttrs(ID, 0, attrs, defAttrs, 0, 6);
 
       tempElem = tempElem.firstChild.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = {"color": gComputedStyle.color};
       testTextAttrs(ID, 6, attrs, defAttrs, 6, 26);
 
       tempElem = tempElem.parentNode;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = {"color": gComputedStyle.color};
       testTextAttrs(ID, 26, attrs, defAttrs, 26, 27);
 
       tempElem = tempElem.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = {"color": gComputedStyle.color,
                "background-color": gComputedStyle.backgroundColor};
       testTextAttrs(ID, 27, attrs, defAttrs, 27, 50);
 
       //////////////////////////////////////////////////////////////////////////
       // area4
       ID = "area4";
       defAttrs = buildDefaultTextAttrs(ID, "12pt");
       testDefaultTextAttrs(ID, defAttrs);
 
       tempElem = getNode(ID).firstChild.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = {"color": gComputedStyle.color};
       testTextAttrs(ID, 0, attrs, defAttrs, 0, 16);
 
       tempElem = tempElem.nextSibling.firstChild.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = {"color": gComputedStyle.color};
       testTextAttrs(ID, 16, attrs, defAttrs, 16, 33);
 
       tempElem = tempElem.parentNode;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = {"color": gComputedStyle.color};
       testTextAttrs(ID, 34, attrs, defAttrs, 33, 46);
 
       //////////////////////////////////////////////////////////////////////////
       // area5: "Green!*!RedNormal"
       ID = "area5";
       defAttrs = buildDefaultTextAttrs(ID, "12pt");
       testDefaultTextAttrs(ID, defAttrs);
 
       // Green
       tempElem = getNode(ID).firstChild.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = {"color": gComputedStyle.color};
       testTextAttrs(ID, 0, attrs, defAttrs, 0, 5);
 
       // br
       attrs = {};
       testTextAttrs(ID, 5, attrs, defAttrs, 5, 6);
 
       // img, embedded accessible, no attributes
@@ -133,17 +133,17 @@
       testTextAttrs(ID, 6, attrs, {}, 6, 7);
 
       // br
       attrs = {};
       testTextAttrs(ID, 7, attrs, defAttrs, 7, 8);
 
       // Red
       tempElem = tempElem.nextSibling.nextSibling.nextSibling.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = {"color": gComputedStyle.color};
       testTextAttrs(ID, 9, attrs, defAttrs, 8, 11);
 
       // Normal
       attrs = {};
       testTextAttrs(ID, 11, attrs, defAttrs, 11, 18);
 
       //////////////////////////////////////////////////////////////////////////
@@ -210,45 +210,45 @@
 
       attrs = {"language": "ru"};
       testTextAttrs(ID, 0, attrs, defAttrs, 0, 6);
 
       attrs = {};
       testTextAttrs(ID, 6, attrs, defAttrs, 6, 7);
 
       tempElem = getNode(ID).firstChild.nextSibling.nextSibling.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = { "background-color": gComputedStyle.backgroundColor};
       testTextAttrs(ID, 13, attrs, defAttrs, 7, 20);
 
       attrs = {};
       testTextAttrs(ID, 20, attrs, defAttrs, 20, 21);
 
       attrs = {"language": "de"};
       testTextAttrs(ID, 21, attrs, defAttrs, 21, 36);
 
       attrs = {};
       testTextAttrs(ID, 36, attrs, defAttrs, 36, 44);
 
       attrs = {};
       testTextAttrs(ID, 37, attrs, defAttrs, 36, 44);
 
       tempElem = tempElem.nextSibling.nextSibling.nextSibling.nextSibling.firstChild.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = {"color": gComputedStyle.color};
       testTextAttrs(ID, 44, attrs, defAttrs, 44, 51);
 
       tempElem = tempElem.firstChild.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = {"font-weight": kBoldFontWeight,
                "color": gComputedStyle.color};
       testTextAttrs(ID, 51, attrs, defAttrs, 51, 55);
 
       tempElem = tempElem.parentNode;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = {"color": gComputedStyle.color};
       testTextAttrs(ID, 55, attrs, defAttrs, 55, 62);
 
       //////////////////////////////////////////////////////////////////////////
       // area9, different single style spans in styled paragraph
       ID = "area9";
       defAttrs = buildDefaultTextAttrs(ID, "10pt");
       testDefaultTextAttrs(ID, defAttrs);
@@ -259,35 +259,35 @@
       attrs = { "font-size": "12pt" };
       testTextAttrs(ID, 7, attrs, defAttrs, 6, 12);
 
       attrs = {};
       testTextAttrs(ID, 13, attrs, defAttrs, 12, 21);
 
       // Walk to the span with the different background color
       tempElem = getNode(ID).firstChild.nextSibling.nextSibling.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = { "background-color": gComputedStyle.backgroundColor };
       testTextAttrs(ID, 22, attrs, defAttrs, 21, 36);
 
       attrs = {};
       testTextAttrs(ID, 37, attrs, defAttrs, 36, 44);
 
       // Walk from the background color span to the one with font-style
       tempElem = tempElem.nextSibling.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = { "font-style": gComputedStyle.fontStyle };
       testTextAttrs(ID, 45, attrs, defAttrs, 44, 61);
 
       attrs = {};
       testTextAttrs(ID, 62, attrs, defAttrs, 61, 69);
 
       // Walk from span with font-style to the one with font-family.
       tempElem = tempElem.nextSibling.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = { "font-family": kMonospaceFontFamily };
       testTextAttrs(ID, 70, attrs, defAttrs, 69, 83);
 
       attrs = {};
       testTextAttrs(ID, 84, attrs, defAttrs, 83, 91);
 
       attrs = {
         "text-underline-style": "solid",
@@ -337,35 +337,35 @@
       attrs = { "font-size": "14pt" };
       testTextAttrs(ID, 7, attrs, defAttrs, 7, 13);
 
       attrs = {};
       testTextAttrs(ID, 13, attrs, defAttrs, 13, 22);
 
       // Walk to the span with the different background color
       tempElem = getNode(ID).firstChild.nextSibling.nextSibling.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = { "background-color": gComputedStyle.backgroundColor };
       testTextAttrs(ID, 23, attrs, defAttrs, 22, 37);
 
       attrs = {};
       testTextAttrs(ID, 38, attrs, defAttrs, 37, 45);
 
       // Walk from the background color span to the one with font-style
       tempElem = tempElem.nextSibling.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = {"font-style": gComputedStyle.fontStyle};
       testTextAttrs(ID, 46, attrs, defAttrs, 45, 62);
 
       attrs = {};
       testTextAttrs(ID, 63, attrs, defAttrs, 62, 70);
 
       // Walk from span with font-style to the one with font-family.
       tempElem = tempElem.nextSibling.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = { "font-family": kMonospaceFontFamily };
       testTextAttrs(ID, 71, attrs, defAttrs, 70, 84);
 
       attrs = {};
       testTextAttrs(ID, 85, attrs, defAttrs, 84, 92);
 
       attrs = {
         "text-underline-style": "solid",
@@ -550,17 +550,17 @@
       // text enclosed in mark tag will have a different background color
       ID = "area19";
       defAttrs = buildDefaultTextAttrs(ID, "12pt");
 
       attrs = {};
       testTextAttrs(ID, 0, attrs, defAttrs, 0, 10);
       
       tempElem = getNode(ID).firstChild.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem);
       attrs = { "background-color": gComputedStyle.backgroundColor };
       testTextAttrs(ID, 11, attrs, defAttrs, 10, 17);
 
       attrs = {};
       testTextAttrs(ID, 18, attrs, defAttrs, 17, 28);
 
        //////////////////////////////////////////////////////////////////////////
       // area20, "aOffset as -1 (Mozilla Bug 789621)" test
--- a/accessible/tests/mochitest/treeupdate/test_ariaowns.html
+++ b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
@@ -218,17 +218,17 @@
         new invokerChecker(EVENT_HIDE, getNode, "t1_checkbox"),
         new invokerChecker(EVENT_SHOW, getNode, "t1_checkbox"),
         new invokerChecker(EVENT_REORDER, getNode("t1_container"))
       ];
 
       this.invoke = function removeEl_invoke()
       {
         // remove a container of t1_subdiv
-        getNode("t1_span").parentNode.removeChild(getNode("t1_span"));
+        getNode("t1_span").remove();
       }
 
       this.finalCheck = function removeEl_finalCheck()
       {
         // subdiv should go away
         var tree =
           { SECTION: [
               { CHECKBUTTON: [ ] }, // explicit, t1_checkbox
@@ -518,25 +518,69 @@
       this.eventSeq = [
         new invokerChecker(EVENT_HIDE, getAccessible(aParent))
       ];
 
       this.invoke = function setARIAOwnsOnElToRemove_invoke()
       {
         getNode(aChild).setAttribute("aria-owns", "no_id");
         getNode(aParent).removeChild(getNode(aChild));
-        getNode(aParent).parentNode.removeChild(getNode(aParent));
+        getNode(aParent).remove();
       }
 
       this.getID = function setARIAOwnsOnElToRemove_getID()
       {
         return `set ARIA owns on an element, and then remove it, and then remove its parent`;
       }
     }
 
+    /**
+     * Set ARIA owns on inaccessible span element that contains
+     * accessible children. This will move children from the container for
+     * the span.
+     */
+    function test8()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_REORDER, "t8_container")
+      ];
+
+      this.invoke = function test8_invoke()
+      {
+        var tree =
+          { SECTION: [
+            { PUSHBUTTON: [] },
+            { ENTRY: [] },
+            { ENTRY: [] },
+            { ENTRY: [] }
+          ] };
+        testAccessibleTree("t8_container", tree);
+
+        getNode(t8_container).setAttribute("aria-owns", "t8_span t8_button");
+      }
+
+      this.finalCheck = function test8_finalCheck()
+      {
+        var tree =
+          { SECTION: [
+            { TEXT: [
+              { ENTRY: [] },
+              { ENTRY: [] },
+              { ENTRY: [] }
+            ] },
+            { PUSHBUTTON: [] }
+          ] };
+        testAccessibleTree("t8_container", tree);
+      }
+
+      this.getID = function test8_getID()
+      {
+        return `Set ARIA owns on inaccessible span element that contains accessible children`;
+      }
+    }
 
     ////////////////////////////////////////////////////////////////////////////
     // Test
     ////////////////////////////////////////////////////////////////////////////
 
     //gA11yEventDumpToConsole = true;
     //enableLogging("tree,eventTree,verbose"); // debug stuff
 
@@ -575,16 +619,18 @@
         "t5_container", "t5_radio t5_button t5_checkbox",
         [ "t5_radio", "t5_button" ],
         [ "RADIOBUTTON", "PUSHBUTTON", "CHECKBUTTON" ]));
 
       gQueue.push(new removeNotARIAOwnedEl("t6_container", "t6_span"));
 
       gQueue.push(new setARIAOwnsOnElToRemove("t7_parent", "t7_child"));
 
+      gQueue.push(new test8());
+
       gQueue.invoke(); // SimpleTest.finish() will be called in the end
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
 
   </script>
 </head>
@@ -633,11 +679,15 @@
   </div>
   <div id="t6_fake" role="group"></div>
 
   <div id="t7_container">
     <div id="t7_parent">
       <div id="t7_child"></div>
     </div>
   </div>
+
+  <div id="t8_container">
+    <input id="t8_button" type="button"><span id="t8_span"><input><input><input></span>
+  </div>
 </body>
 
 </html>
--- a/accessible/tests/mochitest/treeupdate/test_bug1175913.html
+++ b/accessible/tests/mochitest/treeupdate/test_bug1175913.html
@@ -42,28 +42,30 @@
       {
         return "Test that show event is sent when click listener is added";
       }
     }
 
     function testRemoveListener()
     {
       this.eventSeq = [
-        new invokerChecker(EVENT_HIDE, getNode("parent")),
+        new unexpectedInvokerChecker(EVENT_HIDE, getNode("parent")),
       ];
 
       this.invoke = function testRemoveListener_invoke()
       {
         getNode("parent").removeEventListener("click", dummyListener);
       }
 
       this.finalCheck = function testRemoveListener_finalCheck()
       {
-        is(getAccessible("parent", null, null, DONOTFAIL_IF_NO_ACC), null, "Check that parent is not accessible.");
-        is(getAccessible("child", null, null, DONOTFAIL_IF_NO_ACC), null, "Check that child is not accessible.");
+        ok(getAccessible("parent", null, null, DONOTFAIL_IF_NO_ACC),
+           "Parent stays accessible after click event listener is removed");
+        ok(!getAccessible("child", null, null, DONOTFAIL_IF_NO_ACC),
+           "Child stays inaccessible");
       }
 
       this.getID = function testRemoveListener_getID()
       {
         return "Test that hide event is sent when click listener is removed";
       }
     }
 
--- a/accessible/tests/mochitest/treeupdate/test_doc.html
+++ b/accessible/tests/mochitest/treeupdate/test_doc.html
@@ -261,17 +261,17 @@
       this.__proto__ = new rootContentRemoved(aID);
 
       this.invoke = function removeHTMLFromIFrameDoc_invoke()
       {
         this.preinvoke();
 
         // Remove HTML element.
         var docNode = getDocNode(aID);
-        docNode.removeChild(docNode.firstChild);
+        docNode.firstChild.remove();
       }
 
       this.getID = function removeHTMLFromIFrameDoc_getID()
       {
         return "remove HTML element";
       }
     }
 
--- a/accessible/tests/mochitest/treeupdate/test_general.html
+++ b/accessible/tests/mochitest/treeupdate/test_general.html
@@ -59,17 +59,17 @@
     function removeRemove(aContainer)
     {
       this.eventSeq = [
         new invokerChecker(EVENT_REORDER, aContainer)
       ];
 
       this.invoke = function removeRemove_invoke()
       {
-        getNode(aContainer).removeChild(getNode(aContainer).firstChild);
+        getNode(aContainer).firstChild.remove();
       }
 
       this.finalCheck = function removeRemove_finalCheck()
       {
         var accTree =
           { SECTION: [ // container
             { PUSHBUTTON: [ ] }
           ] };
--- a/accessible/tests/mochitest/treeupdate/test_imagemap.html
+++ b/accessible/tests/mochitest/treeupdate/test_imagemap.html
@@ -268,17 +268,17 @@
         new invokerChecker(EVENT_HIDE, getImageMap, this),
         new invokerChecker(EVENT_SHOW, this.imgNode),
         new invokerChecker(EVENT_REORDER, this.container)
       ];
 
       this.invoke = function removeMap_invoke()
       {
         this.imageMap = getAccessible(aImageMapID);
-        this.mapNode.parentNode.removeChild(this.mapNode);
+        this.mapNode.remove();
       }
 
       this.finalCheck = function removeMap_finalCheck()
       {
         var accTree =
           { SECTION: [
             { GRAPHIC: [ ] }
           ] };
--- a/accessible/tests/mochitest/treeupdate/test_optgroup.html
+++ b/accessible/tests/mochitest/treeupdate/test_optgroup.html
@@ -72,17 +72,17 @@
     {
       this.selectNode = getNode(aID);
       this.select = getAccessible(this.selectNode);
       this.selectList = this.select.firstChild;
 
       this.invoke = function removeOptGroup_invoke()
       {
         this.option1Node = this.selectNode.firstChild.firstChild;
-        this.selectNode.removeChild(this.selectNode.firstChild);
+        this.selectNode.firstChild.remove();
       }
 
       this.eventSeq = [
         new invokerChecker(EVENT_REORDER, this.selectList)
       ];
 
       this.finalCheck = function removeOptGroup_finalCheck()
       {
--- a/accessible/tests/mochitest/treeupdate/test_select.html
+++ b/accessible/tests/mochitest/treeupdate/test_select.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <html>
 <head>
-  <title>Add select options test</title>
+  <title>HTML select options test</title>
   <link rel="stylesheet" type="text/css"
         href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <script type="application/javascript"
           src="../common.js"></script>
@@ -86,45 +86,65 @@
       }
 
       this.getID = function removeptions_getID()
       {
         return "test elements removal from a select";
       }
     }
 
-    //gA11yEventDumpID = "debug";
+    /**
+     * Setting @href on option makes the accessible to recreate.
+     */
+    function setHrefOnOption()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, 's2_o'),
+        new invokerChecker(EVENT_SHOW, 's2_o'),
+      ];
+
+      this.invoke = function setHrefOnOption_setHref()
+      {
+        getNode('s2_o').setAttribute('href', '1');
+      }
+
+      this.finalCheck = function() {
+        var tree =
+          { COMBOBOX: [
+            { COMBOBOX_LIST: [
+              { COMBOBOX_OPTION: [ ] }
+            ] }
+          ] };
+        testAccessibleTree('s2', tree);
+      }
+
+      this.getID = function removeptions_getID()
+      {
+        return "setting @href on select option";
+      }
+    }
 
     function doTest()
     {
       gQueue = new eventQueue();
 
       gQueue.push(new addOptions("select"));
       gQueue.push(new removeOptions("select"));
+      gQueue.push(new setHrefOnOption());
 
       gQueue.invoke(); // Will call SimpleTest.finish();
 
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body>
-
-  <a target="_blank"
-     href="https://bugzilla.mozilla.org/show_bug.cgi?id=616452"
-     title="Bug 616452 - Dynamically inserted select options aren't reflected in accessible tree">
-    Mozilla Bug 616452</a>
-  <a target="_blank"
-     href="https://bugzilla.mozilla.org/show_bug.cgi?id=616940"
-     title="Removed select option accessibles aren't removed until hide event is fired">
-    Mozilla Bug 616940</a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <select id="select"></select>
-
-  <div id="debug"/>
+  <select id="s2"><option id="s2_o"></option></select>
 </body>
 </html>
--- a/accessible/tests/mochitest/treeupdate/test_shutdown.xul
+++ b/accessible/tests/mochitest/treeupdate/test_shutdown.xul
@@ -50,17 +50,17 @@
       this.eventSeq = [
         new invokerChecker(EVENT_REORDER, document)
       ];
 
       this.invoke = function invoke()
       {
         this.lastItem = getAccessible(aID).lastChild;
         this.lastCell = this.lastItem.lastChild;
-        getNode(aID).parentNode.removeChild(getNode(aID));
+        getNode(aID).remove();
       };
 
       this.check = function check(aEvent)
       {
         testIsDefunct(this.tree, aID);
         testIsDefunct(this.lastItem, "last item of " + aID);
         if (this.lastCell) {
           testIsDefunct(this.lastCell, "last item cell of " + aID);
--- a/accessible/tests/mochitest/treeupdate/test_textleaf.html
+++ b/accessible/tests/mochitest/treeupdate/test_textleaf.html
@@ -38,32 +38,26 @@
       }
     }
 
     function setOnClickAttr(aID)
     {
       var node = getNode(aID);
       node.setAttribute("onclick", "alert(3);");
       var textLeaf = getAccessible(node).firstChild;
-      is(textLeaf.actionCount, 1, "Wrong action numbers!");
+      is(textLeaf.actionCount, 1, "setOnClickAttr: wrong action numbers!");
     }
 
     function removeOnClickAttr(aID)
     {
-      this.__proto__ = new textLeafUpdate(aID, false);
-
-      this.invoke = function removeOnClickAttr_invoke()
-      {
-        this.node.removeAttribute("onclick");
-      }
-
-      this.getID = function removeOnClickAttr_getID()
-      {
-        return "unmake " + prettyName(aID) + " linkable";
-      }
+      var node = getNode(aID);
+      node.removeAttribute("onclick");
+      var textLeaf = getAccessible(node).firstChild;
+      is(textLeaf.actionCount, 0,
+         "removeOnClickAttr: wrong action numbers!");
     }
 
     function setOnClickNRoleAttrs(aID)
     {
       this.__proto__ = new textLeafUpdate(aID, true);
 
       this.invoke = function setOnClickAttr_invoke()
       {
@@ -124,20 +118,21 @@
     //gA11yEventDumpToConsole = true;
 
     var gQueue = null;
 
     function doTest()
     {
       // adds onclick on element, text leaf should inherit its action
       setOnClickAttr("div");
+      // remove onclick attribute, text leaf shouldn't have any action
+      removeOnClickAttr("div");
+
       // Call rest of event tests.
       gQueue = new eventQueue();
-      // remove onclick attribute, text leaf shouldn't have any action
-      gQueue.push(new removeOnClickAttr("div"));
 
       // set onclick attribute making span accessible, it's inserted into tree
       // and adopts text leaf accessible, text leaf should have an action
       gQueue.push(new setOnClickNRoleAttrs("span"));
 
       // text data removal of text node should remove its text accessible
       gQueue.push(new removeTextData("p", ROLE_PARAGRAPH));
       gQueue.push(new removeTextData("pre", ROLE_TEXT_CONTAINER));
--- a/accessible/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/windows/msaa/AccessibleWrap.cpp
@@ -28,16 +28,17 @@
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
 
 #include "nsIMutableArray.h"
 #include "nsIFrame.h"
 #include "nsIScrollableFrame.h"
 #include "mozilla/dom/NodeInfo.h"
+#include "mozilla/dom/TabParent.h"
 #include "nsIServiceManager.h"
 #include "nsNameSpaceManager.h"
 #include "nsTextFormatter.h"
 #include "nsView.h"
 #include "nsViewManager.h"
 #include "nsEventMap.h"
 #include "nsArrayUtils.h"
 #include "mozilla/Preferences.h"
@@ -85,20 +86,21 @@ AccessibleWrap::~AccessibleWrap()
 ITypeInfo* AccessibleWrap::gTypeInfo = nullptr;
 
 NS_IMPL_ISUPPORTS_INHERITED0(AccessibleWrap, Accessible)
 
 void
 AccessibleWrap::Shutdown()
 {
   if (mID != kNoID) {
-    auto doc = static_cast<DocAccessibleWrap*>(mDoc);
+    auto doc = static_cast<DocAccessibleWrap*>(mDoc.get());
     MOZ_ASSERT(doc);
     if (doc) {
       doc->RemoveID(mID);
+      mID = kNoID;
     }
   }
 
   Accessible::Shutdown();
 }
 
 //-----------------------------------------------------
 // IUnknown interface methods - see iunknown.h for documentation
@@ -1248,25 +1250,35 @@ AccessibleWrap::GetChildIDFor(Accessible
 
 HWND
 AccessibleWrap::GetHWNDFor(Accessible* aAccessible)
 {
   if (!aAccessible) {
     return nullptr;
   }
 
-  // Accessibles in child processes are said to have the HWND of the window
-  // their tab is within.  Popups are always in the parent process, and so
-  // never proxied, which means this is basically correct.
   if (aAccessible->IsProxy()) {
     ProxyAccessible* proxy = aAccessible->Proxy();
     if (!proxy) {
       return nullptr;
     }
 
+    // If window emulation is enabled, retrieve the emulated window from the
+    // containing document document proxy.
+    if (nsWinUtils::IsWindowEmulationStarted()) {
+      DocAccessibleParent* doc = proxy->Document();
+      HWND hWnd = doc->GetEmulatedWindowHandle();
+      if (hWnd) {
+        return hWnd;
+      }
+    }
+
+    // Accessibles in child processes are said to have the HWND of the window
+    // their tab is within.  Popups are always in the parent process, and so
+    // never proxied, which means this is basically correct.
     Accessible* outerDoc = proxy->OuterDocOfRemoteBrowser();
     NS_ASSERTION(outerDoc, "no outer doc for accessible remote tab!");
     if (!outerDoc) {
       return nullptr;
     }
 
     return GetHWNDFor(outerDoc);
   }
@@ -1330,31 +1342,45 @@ GetAccessibleInSubtree(DocAccessible* aD
   }
 
 static already_AddRefed<IDispatch>
 GetProxiedAccessibleInSubtree(const DocAccessibleParent* aDoc,
                               const VARIANT& aVarChild)
 {
   auto wrapper = static_cast<DocProxyAccessibleWrap*>(WrapperFor(aDoc));
   RefPtr<IAccessible> comProxy;
-  int32_t wrapperChildId = AccessibleWrap::GetChildIDFor(wrapper);
-  if (wrapperChildId == aVarChild.lVal) {
+  int32_t docWrapperChildId = AccessibleWrap::GetChildIDFor(wrapper);
+  // Only top level document accessible proxies are created with a pointer to
+  // their COM proxy.
+  if (aDoc->IsTopLevel()) {
     wrapper->GetNativeInterface(getter_AddRefs(comProxy));
-    return comProxy.forget();
+  } else {
+    auto tab = static_cast<dom::TabParent*>(aDoc->Manager());
+    MOZ_ASSERT(tab);
+    DocAccessibleParent* topLevelDoc = tab->GetTopLevelDocAccessible();
+    MOZ_ASSERT(topLevelDoc && topLevelDoc->IsTopLevel());
+    VARIANT docId = {VT_I4};
+    docId.lVal = docWrapperChildId;
+    RefPtr<IDispatch> disp = GetProxiedAccessibleInSubtree(topLevelDoc, docId);
+    if (!disp) {
+      return nullptr;
+    }
+
+    DebugOnly<HRESULT> hr = disp->QueryInterface(IID_IAccessible,
+                                                 getter_AddRefs(comProxy));
+    MOZ_ASSERT(SUCCEEDED(hr));
   }
 
-  MOZ_ASSERT(aDoc->IsTopLevel());
-  if (!aDoc->IsTopLevel()) {
+  MOZ_ASSERT(comProxy);
+  if (!comProxy) {
     return nullptr;
   }
 
-  wrapper->GetNativeInterface(getter_AddRefs(comProxy));
-  MOZ_ASSERT(comProxy);
-  if (!comProxy) {
-    return nullptr;
+  if (docWrapperChildId == aVarChild.lVal) {
+    return comProxy.forget();
   }
 
   RefPtr<IDispatch> disp;
   if (FAILED(comProxy->get_accChild(aVarChild, getter_AddRefs(disp)))) {
     return nullptr;
   }
 
   return disp.forget();
@@ -1388,23 +1414,28 @@ AccessibleWrap::GetIAccessibleFor(const 
       return nullptr;
     }
     // Otherwise, since we're a proxy and we have a null native interface, this
     // indicates that we need to obtain a COM proxy. To do this, we'll replace
     // CHILDID_SELF with our real MSAA ID and continue the search from there.
     varChild.lVal = GetExistingID();
   }
 
-  if (IsProxy() ? Proxy()->MustPruneChildren() : nsAccUtils::MustPrune(this)) {
+  if (varChild.ulVal != GetExistingID() &&
+      (IsProxy() ? Proxy()->MustPruneChildren() : nsAccUtils::MustPrune(this))) {
+    // This accessible should have no subtree in platform, return null for its children.
     return nullptr;
   }
 
   // If the MSAA ID is not a chrome id then we already know that we won't
-  // find it here and should look remotely instead.
-  if (XRE_IsParentProcess() && !sIDGen.IsChromeID(varChild.lVal)) {
+  // find it here and should look remotely instead. This handles the case when
+  // accessible is part of the chrome process and is part of the xul browser
+  // window and the child id points in the content documents. Thus we need to
+  // make sure that it is never called on proxies.
+  if (XRE_IsParentProcess() && !IsProxy() && !sIDGen.IsChromeID(varChild.lVal)) {
     return GetRemoteIAccessibleFor(varChild);
   }
   MOZ_ASSERT(XRE_IsParentProcess() ||
              sIDGen.IsIDForThisContentProcess(varChild.lVal));
 
   if (varChild.lVal > 0) {
     // Gecko child indices are 0-based in contrast to indices used in MSAA.
     MOZ_ASSERT(!IsProxy());
@@ -1465,17 +1496,16 @@ AccessibleWrap::GetIAccessibleFor(const 
   }
 
   return nullptr;
 }
 
 already_AddRefed<IAccessible>
 AccessibleWrap::GetRemoteIAccessibleFor(const VARIANT& aVarChild)
 {
-  DocAccessibleParent* proxyDoc = nullptr;
   DocAccessible* doc = Document();
   const nsTArray<DocAccessibleParent*>* remoteDocs =
     DocManager::TopLevelRemoteDocs();
   if (!remoteDocs) {
     return nullptr;
   }
 
   RefPtr<IAccessible> result;
--- a/accessible/windows/msaa/DocAccessibleWrap.cpp
+++ b/accessible/windows/msaa/DocAccessibleWrap.cpp
@@ -48,17 +48,24 @@ STDMETHODIMP
 DocAccessibleWrap::get_accParent(
       /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispParent)
 {
   // We might be a top-level document in a content process.
   DocAccessibleChild* ipcDoc = IPCDoc();
   if (!ipcDoc) {
     return DocAccessible::get_accParent(ppdispParent);
   }
-  IAccessible* dispParent = ipcDoc->GetParentIAccessible();
+
+  // Emulated window proxy is only set for the top level content document when
+  // emulation is enabled.
+  IAccessible* dispParent = ipcDoc->GetEmulatedWindowIAccessible();
+  if (!dispParent) {
+    dispParent = ipcDoc->GetParentIAccessible();
+  }
+
   if (!dispParent) {
     return S_FALSE;
   }
 
   dispParent->AddRef();
   *ppdispParent = static_cast<IDispatch*>(dispParent);
   return S_OK;
 }
@@ -115,18 +122,31 @@ DocAccessibleWrap::Shutdown()
 ////////////////////////////////////////////////////////////////////////////////
 // DocAccessible public
 
 void*
 DocAccessibleWrap::GetNativeWindow() const
 {
   if (XRE_IsContentProcess()) {
     DocAccessibleChild* ipcDoc = IPCDoc();
+    if (!ipcDoc) {
+      return nullptr;
+    }
+
+    HWND hWnd = ipcDoc->GetEmulatedWindowHandle();
+    if (hWnd) {
+      return hWnd;
+    }
+
     auto tab = static_cast<dom::TabChild*>(ipcDoc->Manager());
     MOZ_ASSERT(tab);
+    if (!tab) {
+      return nullptr;
+    }
+
     return reinterpret_cast<HWND>(tab->GetNativeWindowHandle());
   } else if (mHWND) {
     return mHWND;
   }
   return DocAccessible::GetNativeWindow();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/windows/msaa/GeckoCustom.cpp
+++ b/accessible/windows/msaa/GeckoCustom.cpp
@@ -15,14 +15,45 @@ IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mAcc
 
 HRESULT
 GeckoCustom::get_anchorCount(long* aCount)
 {
   *aCount = mAcc->AnchorCount();
   return S_OK;
 }
 
+HRESULT
+GeckoCustom::get_DOMNodeID(BSTR* aID)
+{
+  nsIContent* content = mAcc->GetContent();
+  if (!content) {
+    return S_OK;
+  }
+
+  nsIAtom* id = content->GetID();
+  if (id) {
+    nsAutoString idStr;
+    id->ToString(idStr);
+    *aID = ::SysAllocStringLen(idStr.get(), idStr.Length());
+  }
+  return S_OK;
+}
+
 STDMETHODIMP
 GeckoCustom::get_ID(uint64_t* aID)
 {
   *aID = mAcc->IsDoc() ? 0 : reinterpret_cast<uintptr_t>(mAcc.get());
   return S_OK;
 }
+
+STDMETHODIMP
+GeckoCustom::get_minimumIncrement(double* aIncrement)
+{
+  *aIncrement = mAcc->Step();
+  return S_OK;
+}
+
+STDMETHODIMP
+GeckoCustom::get_mozState(uint64_t* aState)
+{
+  *aState = mAcc->State();
+  return S_OK;
+}
--- a/accessible/windows/msaa/GeckoCustom.h
+++ b/accessible/windows/msaa/GeckoCustom.h
@@ -22,17 +22,20 @@ class GeckoCustom final : public IGeckoC
 {
 public:
   explicit GeckoCustom(AccessibleWrap* aAcc) : mAcc(aAcc) {}
 
   // IUnknown
   DECL_IUNKNOWN
 
   virtual STDMETHODIMP get_anchorCount(long* aCount);
+  virtual STDMETHODIMP get_DOMNodeID(BSTR* aID);
   virtual STDMETHODIMP get_ID(uint64_t* aID);
+  virtual STDMETHODIMP get_minimumIncrement(double* aIncrement);
+  virtual STDMETHODIMP get_mozState(uint64_t* aState);
 
 private:
   GeckoCustom() = delete;
   GeckoCustom& operator =(const GeckoCustom&) = delete;
   GeckoCustom(const GeckoCustom&) = delete;
   GeckoCustom(GeckoCustom&&) = delete;
   GeckoCustom& operator=(GeckoCustom&&) = delete;
 
--- a/accessible/windows/msaa/Platform.cpp
+++ b/accessible/windows/msaa/Platform.cpp
@@ -17,29 +17,33 @@
 #include "mozilla/mscom/Registration.h"
 #include "mozilla/StaticPtr.h"
 #include "ProxyWrappers.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 using namespace mozilla::mscom;
 
+static StaticAutoPtr<RegisteredProxy> gRegCustomProxy;
 static StaticAutoPtr<RegisteredProxy> gRegProxy;
 static StaticAutoPtr<RegisteredProxy> gRegAccTlb;
 static StaticAutoPtr<RegisteredProxy> gRegMiscTlb;
 
 void
 a11y::PlatformInit()
 {
   Compatibility::Init();
 
   nsWinUtils::MaybeStartWindowEmulation();
   ia2AccessibleText::InitTextChangeData();
   if (BrowserTabsRemoteAutostart()) {
     mscom::InterceptorLog::Init();
+    UniquePtr<RegisteredProxy> regCustomProxy(
+        mscom::RegisterProxy());
+    gRegCustomProxy = regCustomProxy.release();
     UniquePtr<RegisteredProxy> regProxy(
         mscom::RegisterProxy(L"ia2marshal.dll"));
     gRegProxy = regProxy.release();
     UniquePtr<RegisteredProxy> regAccTlb(
         mscom::RegisterTypelib(L"oleacc.dll",
                                RegistrationFlags::eUseSystemDirectory));
     gRegAccTlb = regAccTlb.release();
     UniquePtr<RegisteredProxy> regMiscTlb(
@@ -49,16 +53,17 @@ a11y::PlatformInit()
 }
 
 void
 a11y::PlatformShutdown()
 {
   ::DestroyCaret();
 
   nsWinUtils::ShutdownWindowEmulation();
+  gRegCustomProxy = nullptr;
   gRegProxy = nullptr;
   gRegAccTlb = nullptr;
   gRegMiscTlb = nullptr;
 }
 
 void
 a11y::ProxyCreated(ProxyAccessible* aProxy, uint32_t aInterfaces)
 {
@@ -80,16 +85,20 @@ void
 a11y::ProxyDestroyed(ProxyAccessible* aProxy)
 {
   AccessibleWrap* wrapper =
     reinterpret_cast<AccessibleWrap*>(aProxy->GetWrapper());
   MOZ_ASSERT(wrapper);
   if (!wrapper)
     return;
 
+  if (aProxy->IsDoc() && nsWinUtils::IsWindowEmulationStarted()) {
+    aProxy->AsDoc()->SetEmulatedWindowHandle(nullptr);
+  }
+
   wrapper->Shutdown();
   aProxy->SetWrapper(0);
   wrapper->Release();
 }
 
 void
 a11y::ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType)
 {
--- a/accessible/windows/msaa/ServiceProvider.cpp
+++ b/accessible/windows/msaa/ServiceProvider.cpp
@@ -2,27 +2,26 @@
 /* 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 "ServiceProvider.h"
 
 #include "ApplicationAccessibleWrap.h"
-#include "Compatibility.h"
 #include "DocAccessible.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "Relation.h"
 #include "uiaRawElmProvider.h"
 
 #include "mozilla/Preferences.h"
 #include "nsIDocShell.h"
 
-#include "ISimpleDOMNode_i.c"
+#include "ISimpleDOM.h"
 
 namespace mozilla {
 namespace a11y {
 
 IMPL_IUNKNOWN_QUERY_HEAD(ServiceProvider)
   IMPL_IUNKNOWN_QUERY_IFACE(IServiceProvider)
 IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mAccessible)
 
@@ -67,18 +66,20 @@ ServiceProvider::QueryService(REFGUID aG
       return E_NOINTERFACE;
 
     *aInstancePtr = static_cast<IAccessible*>(tabDoc);
     (reinterpret_cast<IUnknown*>(*aInstancePtr))->AddRef();
     return S_OK;
   }
 
   // Can get to IAccessibleApplication from any node via QS
+  // Note: in case of JAWS we want to check if aIID is
+  // IID_IAccessibleApplication.
   if (aGuidService == IID_IAccessibleApplication ||
-      (Compatibility::IsJAWS() && aIID == IID_IAccessibleApplication)) {
+      aIID == IID_IAccessibleApplication) {
     ApplicationAccessibleWrap* applicationAcc =
       static_cast<ApplicationAccessibleWrap*>(ApplicationAcc());
     if (!applicationAcc)
       return E_NOINTERFACE;
 
     return applicationAcc->QueryInterface(aIID, aInstancePtr);
   }
 
--- a/accessible/windows/msaa/moz.build
+++ b/accessible/windows/msaa/moz.build
@@ -9,16 +9,17 @@ EXPORTS += [
 ]
 
 EXPORTS.mozilla.a11y += [
     'AccessibleWrap.h',
     'Compatibility.h',
     'HyperTextAccessibleWrap.h',
     'IDSet.h',
     'MsaaIdGenerator.h',
+    'nsWinUtils.h',
 ]
 
 UNIFIED_SOURCES += [
     'AccessibleWrap.cpp',
     'ApplicationAccessibleWrap.cpp',
     'ARIAGridAccessibleWrap.cpp',
     'Compatibility.cpp',
     'DocAccessibleWrap.cpp',
--- a/accessible/windows/msaa/nsWinUtils.cpp
+++ b/accessible/windows/msaa/nsWinUtils.cpp
@@ -7,24 +7,26 @@
 
 #include "nsWinUtils.h"
 
 #include "Compatibility.h"
 #include "DocAccessible.h"
 #include "nsAccessibilityService.h"
 #include "nsCoreUtils.h"
 
+#include "mozilla/a11y/DocAccessibleParent.h"
 #include "mozilla/Preferences.h"
 #include "nsArrayUtils.h"
 #include "nsIArray.h"
 #include "nsICSSDeclaration.h"
 #include "nsIDocument.h"
 #include "nsIDocShellTreeItem.h"
 #include "mozilla/dom/Element.h"
 #include "nsXULAppAPI.h"
+#include "ProxyWrappers.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 using mozilla::dom::Element;
 
 // Window property used by ipc related code in identifying accessible
 // tab windows.
 const wchar_t* kPropNameTabContent = L"AccessibleTabWindow";
@@ -148,28 +150,35 @@ WindowProc(HWND hWnd, UINT msg, WPARAM w
 
   switch (msg) {
     case WM_GETOBJECT:
     {
       // Do explicit casting to make it working on 64bit systems (see bug 649236
       // for details).
       int32_t objId = static_cast<DWORD>(lParam);
       if (objId == OBJID_CLIENT) {
+        IAccessible* msaaAccessible = nullptr;
         DocAccessible* document =
           reinterpret_cast<DocAccessible*>(::GetPropW(hWnd, kPropNameDocAcc));
         if (document) {
-          IAccessible* msaaAccessible = nullptr;
           document->GetNativeInterface((void**)&msaaAccessible); // does an addref
-          if (msaaAccessible) {
-            LRESULT result = ::LresultFromObject(IID_IAccessible, wParam,
-                                                 msaaAccessible); // does an addref
-            msaaAccessible->Release(); // release extra addref
-            return result;
+        } else {
+          DocAccessibleParent* docParent = static_cast<DocAccessibleParent*>(
+            ::GetPropW(hWnd, kPropNameDocAccParent));
+          if (docParent) {
+            auto wrapper = WrapperFor(docParent);
+            wrapper->GetNativeInterface((void**)&msaaAccessible); // does an addref
           }
         }
+        if (msaaAccessible) {
+          LRESULT result = ::LresultFromObject(IID_IAccessible, wParam,
+                                               msaaAccessible); // does an addref
+          msaaAccessible->Release(); // release extra addref
+          return result;
+        }
       }
       return 0;
     }
     case WM_NCHITTEST:
     {
       LRESULT lRet = ::DefWindowProc(hWnd, msg, wParam, lParam);
       if (HTCLIENT == lRet)
         lRet = HTTRANSPARENT;
--- a/accessible/windows/msaa/nsWinUtils.h
+++ b/accessible/windows/msaa/nsWinUtils.h
@@ -18,16 +18,17 @@ class nsIContent;
 namespace mozilla {
 namespace a11y {
 
 class DocAccessible;
 
 const LPCWSTR kClassNameRoot = L"MozillaUIWindowClass";
 const LPCWSTR kClassNameTabContent = L"MozillaContentWindowClass";
 const LPCWSTR kPropNameDocAcc = L"MozDocAccessible";
+const LPCWSTR kPropNameDocAccParent = L"MozDocAccessibleParent";
 
 class nsWinUtils
 {
 public:
   /**
    * Return computed styles declaration for the given node.
    *
    * @note Please use it carefully since it can shutdown the accessible tree
--- a/accessible/windows/sdn/sdnAccessible.cpp
+++ b/accessible/windows/sdn/sdnAccessible.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "sdnAccessible-inl.h"
-#include "ISimpleDOMNode_i.c"
+#include "ISimpleDOM_i.c"
 
 #include "DocAccessibleWrap.h"
 
 #include "nsAttrName.h"
 #include "nsCoreUtils.h"
 #include "nsIAccessibleTypes.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMCSSStyleDeclaration.h"
@@ -161,39 +161,37 @@ sdnAccessible::get_attributesForNames(un
     return E_INVALIDARG;
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   if (!mNode->IsElement())
     return S_FALSE;
 
-  nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(mNode));
+  dom::Element* domElement = mNode->AsElement();
   nsNameSpaceManager* nameSpaceManager = nsNameSpaceManager::GetInstance();
 
   int32_t index = 0;
   for (index = 0; index < aMaxAttribs; index++) {
     aAttribValues[index] = nullptr;
     if (aAttribNames[index]) {
       nsAutoString attributeValue, nameSpaceURI;
       nsAutoString attributeName(nsDependentString(
         static_cast<const wchar_t*>(aAttribNames[index])));
 
-      nsresult rv = NS_OK;
       if (aNameSpaceID[index]>0 &&
         NS_SUCCEEDED(nameSpaceManager->GetNameSpaceURI(aNameSpaceID[index],
                                                        nameSpaceURI))) {
-          rv = domElement->GetAttributeNS(nameSpaceURI, attributeName,
+          domElement->GetAttributeNS(nameSpaceURI, attributeName,
                                           attributeValue);
       } else {
-        rv = domElement->GetAttribute(attributeName, attributeValue);
+        domElement->GetAttribute(attributeName, attributeValue);
       }
 
-      if (NS_SUCCEEDED(rv))
-        aAttribValues[index] = ::SysAllocString(attributeValue.get());
+      aAttribValues[index] = ::SysAllocString(attributeValue.get());
     }
   }
 
   return S_OK;
 }
 
 STDMETHODIMP
 sdnAccessible::get_computedStyle(unsigned short aMaxStyleProperties,
--- a/accessible/windows/sdn/sdnAccessible.h
+++ b/accessible/windows/sdn/sdnAccessible.h
@@ -2,17 +2,17 @@
 /* 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_sdnAccessible_h_
 #define mozilla_a11y_sdnAccessible_h_
 
-#include "ISimpleDOMNode.h"
+#include "ISimpleDOM.h"
 #include "AccessibleWrap.h"
 #include "IUnknownImpl.h"
 
 #include "mozilla/Attributes.h"
 
 namespace mozilla {
 namespace a11y {
 
--- a/accessible/windows/sdn/sdnDocAccessible.cpp
+++ b/accessible/windows/sdn/sdnDocAccessible.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "sdnDocAccessible.h"
 
-#include "ISimpleDOMDocument_i.c"
+#include "ISimpleDOM.h"
 
 #include "nsNameSpaceManager.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // sdnDocAccessible
--- a/accessible/windows/sdn/sdnDocAccessible.h
+++ b/accessible/windows/sdn/sdnDocAccessible.h
@@ -2,17 +2,17 @@
 /* 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_sdnDocAccessible_h_
 #define mozilla_a11y_sdnDocAccessible_h_
 
-#include "ISimpleDOMDocument.h"
+#include "ISimpleDOM.h"
 #include "IUnknownImpl.h"
 
 #include "DocAccessibleWrap.h"
 
 namespace mozilla {
 namespace a11y {
 
 class sdnDocAccessible final : public ISimpleDOMDocument
--- a/accessible/windows/sdn/sdnTextAccessible.cpp
+++ b/accessible/windows/sdn/sdnTextAccessible.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "sdnTextAccessible.h"
 
-#include "ISimpleDOMText_i.c"
+#include "ISimpleDOM.h"
 
 #include "nsCoreUtils.h"
 #include "DocAccessible.h"
 
 #include "nsIFrame.h"
 #include "nsFontMetrics.h"
 #include "nsPresContext.h"
 #include "nsLayoutUtils.h"
--- a/accessible/windows/sdn/sdnTextAccessible.h
+++ b/accessible/windows/sdn/sdnTextAccessible.h
@@ -2,17 +2,17 @@
 /* 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_sdnTextAccessible_h_
 #define mozilla_a11y_sdnTextAccessible_h_
 
-#include "ISimpleDOMText.h"
+#include "ISimpleDOM.h"
 #include "IUnknownImpl.h"
 
 #include "AccessibleWrap.h"
 
 class nsIFrame;
 struct nsPoint;
 
 namespace mozilla {
--- a/accessible/xpcom/xpcAccessible.cpp
+++ b/accessible/xpcom/xpcAccessible.cpp
@@ -190,30 +190,26 @@ xpcAccessible::GetDOMNode(nsIDOMNode** a
     CallQueryInterface(node, aDOMNode);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetId(nsAString& aID)
 {
-#if defined(XP_WIN)
-  return NS_ERROR_NOT_IMPLEMENTED;
-#else
   ProxyAccessible* proxy = IntlGeneric().AsProxy();
   if (!proxy) {
     return NS_ERROR_FAILURE;
   }
 
   nsString id;
   proxy->DOMNodeID(id);
   aID.Assign(id);
 
   return NS_OK;
-#endif
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetDocument(nsIAccessibleDocument** aDocument)
 {
   NS_ENSURE_ARG_POINTER(aDocument);
   *aDocument = nullptr;
 
@@ -503,26 +499,22 @@ xpcAccessible::GetRelationByType(uint32_
     return NS_ERROR_FAILURE;
 
   if (IntlGeneric().IsAccessible()) {
     Relation rel = Intl()->RelationByType(static_cast<RelationType>(aType));
     NS_ADDREF(*aRelation = new nsAccessibleRelation(aType, &rel));
     return NS_OK;
   }
 
-#if defined(XP_WIN)
-  return NS_ERROR_NOT_IMPLEMENTED;
-#else
   ProxyAccessible* proxy = IntlGeneric().AsProxy();
   nsTArray<ProxyAccessible*> targets =
     proxy->RelationByType(static_cast<RelationType>(aType));
   NS_ADDREF(*aRelation = new nsAccessibleRelation(aType, &targets));
 
   return NS_OK;
-#endif
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetRelations(nsIArray** aRelations)
 {
   NS_ENSURE_ARG_POINTER(aRelations);
   *aRelations = nullptr;
 
--- a/accessible/xpcom/xpcAccessibleValue.cpp
+++ b/accessible/xpcom/xpcAccessibleValue.cpp
@@ -114,20 +114,16 @@ xpcAccessibleValue::GetMinimumIncrement(
 
   if (Intl().IsAccessible() && Intl().AsAccessible()->IsDefunct())
     return NS_ERROR_FAILURE;
 
   double value;
   if (Intl().IsAccessible()) {
     value = Intl().AsAccessible()->Step();
   } else {
-#if defined(XP_WIN)
-    return NS_ERROR_NOT_IMPLEMENTED;
-#else
     value = Intl().AsProxy()->Step();
-#endif
   }
 
   if (!IsNaN(value))
     *aValue = value;
 
   return NS_OK;
 }
--- a/accessible/xul/XULMenuAccessible.cpp
+++ b/accessible/xul/XULMenuAccessible.cpp
@@ -209,17 +209,20 @@ XULMenuitemAccessible::KeyboardShortcut(
   uint32_t key = 0;
 
   nsAutoString keyStr;
   keyElm->GetAttr(kNameSpaceID_None, nsGkAtoms::key, keyStr);
   if (keyStr.IsEmpty()) {
     nsAutoString keyCodeStr;
     keyElm->GetAttr(kNameSpaceID_None, nsGkAtoms::keycode, keyCodeStr);
     nsresult errorCode;
-    key = keyStr.ToInteger(&errorCode, kAutoDetect);
+    key = keyStr.ToInteger(&errorCode, kRadix10);
+    if (NS_FAILED(errorCode)) {
+      key = keyStr.ToInteger(&errorCode, kRadix16);
+    }
   } else {
     key = keyStr[0];
   }
 
   nsAutoString modifiersStr;
   keyElm->GetAttr(kNameSpaceID_None, nsGkAtoms::modifiers, modifiersStr);
 
   uint32_t modifierMask = 0;
--- a/accessible/xul/XULTabAccessible.cpp
+++ b/accessible/xul/XULTabAccessible.cpp
@@ -10,26 +10,29 @@
 #include "Role.h"
 #include "States.h"
 
 // NOTE: alphabetically ordered
 #include "nsIDocument.h"
 #include "nsIDOMXULSelectCntrlEl.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIDOMXULRelatedElement.h"
+#include "nsXULElement.h"
+
+#include "mozilla/dom/BindingDeclarations.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTabAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 XULTabAccessible::
   XULTabAccessible(nsIContent* aContent, DocAccessible* aDoc) :
-  AccessibleWrap(aContent, aDoc)
+  HyperTextAccessibleWrap(aContent, aDoc)
 {
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTabAccessible: Accessible
 
 uint8_t
 XULTabAccessible::ActionCount()
@@ -43,19 +46,20 @@ XULTabAccessible::ActionNameAt(uint8_t a
   if (aIndex == eAction_Switch)
     aName.AssignLiteral("switch");
 }
 
 bool
 XULTabAccessible::DoAction(uint8_t index)
 {
   if (index == eAction_Switch) {
-    nsCOMPtr<nsIDOMXULElement> tab(do_QueryInterface(mContent));
+    // XXXbz Could this just FromContent?
+    RefPtr<nsXULElement> tab = nsXULElement::FromContentOrNull(mContent);
     if (tab) {
-      tab->Click();
+      tab->Click(mozilla::dom::CallerType::System);
       return true;
     }
   }
   return false;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTabAccessible: Accessible
--- a/accessible/xul/XULTabAccessible.h
+++ b/accessible/xul/XULTabAccessible.h
@@ -2,26 +2,27 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_XULTabAccessible_h__
 #define mozilla_a11y_XULTabAccessible_h__
 
 // NOTE: alphabetically ordered
+#include "HyperTextAccessibleWrap.h"
 #include "XULMenuAccessible.h"
 #include "XULSelectControlAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 /**
  * An individual tab, xul:tab element.
  */
-class XULTabAccessible : public AccessibleWrap
+class XULTabAccessible : public HyperTextAccessibleWrap
 {
 public:
   enum { eAction_Switch = 0 };
 
   XULTabAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
   virtual a11y::role NativeRole() override;
--- a/accessible/xul/XULTreeAccessible.cpp
+++ b/accessible/xul/XULTreeAccessible.cpp
@@ -860,16 +860,17 @@ XULTreeItemAccessibleBase::DoAction(uint
 // XULTreeItemAccessibleBase: Accessible implementation
 
 void
 XULTreeItemAccessibleBase::Shutdown()
 {
   mTree = nullptr;
   mTreeView = nullptr;
   mRow = -1;
+  mParent = nullptr; // null-out to prevent base class's shutdown ops
 
   AccessibleWrap::Shutdown();
 }
 
 GroupPos
 XULTreeItemAccessibleBase::GroupPosition()
 {
   GroupPos groupPos;
--- a/accessible/xul/XULTreeGridAccessible.cpp
+++ b/accessible/xul/XULTreeGridAccessible.cpp
@@ -450,16 +450,28 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTr
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeGridCellAccessible)
 NS_INTERFACE_MAP_END_INHERITING(LeafAccessible)
 NS_IMPL_ADDREF_INHERITED(XULTreeGridCellAccessible, LeafAccessible)
 NS_IMPL_RELEASE_INHERITED(XULTreeGridCellAccessible, LeafAccessible)
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeGridCellAccessible: Accessible
 
+void
+XULTreeGridCellAccessible::Shutdown()
+{
+  mTree = nullptr;
+  mTreeView = nullptr;
+  mRow = -1;
+  mColumn = nullptr;
+  mParent = nullptr; // null-out to prevent base class's shutdown ops
+
+  LeafAccessible::Shutdown();
+}
+
 Accessible*
 XULTreeGridCellAccessible::FocusedChild()
 {
   return nullptr;
 }
 
 ENameValueFlag
 XULTreeGridCellAccessible::Name(nsString& aName)
--- a/accessible/xul/XULTreeGridAccessible.h
+++ b/accessible/xul/XULTreeGridAccessible.h
@@ -119,16 +119,17 @@ public:
                             int32_t aRow, nsITreeColumn* aColumn);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(XULTreeGridCellAccessible,
                                            LeafAccessible)
 
   // Accessible
+  virtual void Shutdown() override;
   virtual TableCellAccessible* AsTableCell() override { return this; }
   virtual nsIntRect Bounds() const override;
   virtual ENameValueFlag Name(nsString& aName) override;
   virtual Accessible* FocusedChild() override;
   virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() override;
   virtual int32_t IndexInParent() const override;
   virtual Relation RelationByType(RelationType aType) override;
   virtual a11y::role NativeRole() override;
--- a/accessible/xul/moz.build
+++ b/accessible/xul/moz.build
@@ -19,16 +19,18 @@ UNIFIED_SOURCES += [
     'XULTreeGridAccessible.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/accessible/base',
     '/accessible/generic',
     '/accessible/html',
     '/accessible/xpcom',
+    '/dom/base',
+    '/dom/xul',
     '/layout/generic',
     '/layout/xul',
     '/layout/xul/tree',
 ]
 
 if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
     LOCAL_INCLUDES += [
         '/accessible/atk',
--- a/addon-sdk/source/app-extension/bootstrap.js
+++ b/addon-sdk/source/app-extension/bootstrap.js
@@ -111,17 +111,17 @@ function startup(data, reasonCode) {
 
     let domain = id.
       toLowerCase().
       replace(/@/g, '-at-').
       replace(/\./g, '-dot-').
       replace(uuidRe, '$1');
 
     let prefixURI = 'resource://' + domain + '/';
-    let resourcesURI = ioService.newURI(rootURI + '/resources/', null, null);
+    let resourcesURI = ioService.newURI(rootURI + '/resources/');
     setResourceSubstitution(domain, resourcesURI);
 
     // Create path to URLs mapping supported by loader.
     let paths = {
       // Relative modules resolve to add-on package lib
       './': prefixURI + name + '/lib/',
       './tests/': prefixURI + name + '/tests/',
       '': 'resource://gre/modules/commonjs/'
@@ -174,17 +174,17 @@ function startup(data, reasonCode) {
 
       // On mobile, file URI has to end with a `/` otherwise, setSubstitution
       // takes the parent folder instead.
       if (fileURI[fileURI.length-1] !== '/')
         fileURI += '/';
 
       // Maps the given file:// URI to a resource:// in order to avoid various
       // failure that happens with file:// URI and be close to production env
-      let resourcesURI = ioService.newURI(fileURI, null, null);
+      let resourcesURI = ioService.newURI(fileURI);
       let resName = 'extensions.modules.' + domain + '.commonjs.path' + name;
       setResourceSubstitution(resName, resourcesURI);
 
       result[path] = 'resource://' + resName + '/';
       return result;
     }, paths);
 
     // Make version 2 of the manifest
--- a/addon-sdk/source/lib/dev/toolbox.js
+++ b/addon-sdk/source/lib/dev/toolbox.js
@@ -22,17 +22,17 @@ const { gDevTools } = Cu.import("resourc
 // shipped in nightly, after which it can be removed. Bug 1038517
 const registerSDKURI = () => {
   const ioService = Cc['@mozilla.org/network/io-service;1']
                       .getService(Ci.nsIIOService);
   const resourceHandler = ioService.getProtocolHandler("resource")
                                    .QueryInterface(Ci.nsIResProtocolHandler);
 
   const uri = module.uri.replace("dev/toolbox.js", "");
-  resourceHandler.setSubstitution("sdk", ioService.newURI(uri, null, null));
+  resourceHandler.setSubstitution("sdk", ioService.newURI(uri));
 };
 
 registerSDKURI();
 
 const Tool = Class({
   extends: Disposable,
   setup: function(params={}) {
     const { panels } = validate(this, params);
--- a/addon-sdk/source/lib/framescript/content.jsm
+++ b/addon-sdk/source/lib/framescript/content.jsm
@@ -69,17 +69,17 @@ cpmm.addMessageListener('sdk/remote/proc
 })
 
 
 var frames = new Set();
 
 this.registerContentFrame = contentFrame => {
   contentFrame.addEventListener("unload", () => {
     unregisterContentFrame(contentFrame);
-  }, false);
+  });
 
   frames.add(contentFrame);
 
   for (let addon of addons.values()) {
     if ("child" in addon)
       addon.child.registerContentFrame(contentFrame);
   }
 };
--- a/addon-sdk/source/lib/framescript/context-menu.js
+++ b/addon-sdk/source/lib/framescript/context-menu.js
@@ -57,21 +57,21 @@ const SVG_NS = "http://www.w3.org/2000/s
 // directly. If the media is actually audio, be smarter and provide a
 // context menu with audio operations.
 // Source: https://github.com/mozilla/gecko-dev/blob/28c2fca3753c5371643843fc2f2f205146b083b7/browser/base/content/nsContextMenu.js#L632-L637
 const isVideoLoadingAudio = node =>
   node.readyState >= node.HAVE_METADATA &&
     (node.videoWidth == 0 || node.videoHeight == 0)
 
 const isVideo = node =>
-  node instanceof node.ownerDocument.defaultView.HTMLVideoElement &&
+  node instanceof node.ownerGlobal.HTMLVideoElement &&
   !isVideoLoadingAudio(node);
 
 const isAudio = node => {
-  const {HTMLVideoElement, HTMLAudioElement} = node.ownerDocument.defaultView;
+  const {HTMLVideoElement, HTMLAudioElement} = node.ownerGlobal;
   return node instanceof HTMLAudioElement ? true :
          node instanceof HTMLVideoElement ? isVideoLoadingAudio(node) :
          false;
 };
 
 const isImage = ({namespaceURI, localName}) =>
   namespaceURI === HTML_NS && localName === "img" ? true :
   namespaceURI === XUL_NS && localName === "image" ? true :
@@ -160,22 +160,22 @@ const nonPageElements = ["a", "applet", 
 const nonPageSelector = nonPageElements.
                           concat(nonPageElements.map(tag => `${tag} *`)).
                           join(", ");
 
 // Note: isPageContext implementation could have actually used SelectorMatch reader,
 // but old implementation was also checked for collapsed selection there for to keep
 // the behavior same we end up implementing a new reader.
 parsers["reader/isPage()"] = constant(node =>
-  node.ownerDocument.defaultView.getSelection().isCollapsed &&
+  node.ownerGlobal.getSelection().isCollapsed &&
   !node.matches(nonPageSelector));
 
 // Reads `true` if node is in an iframe otherwise returns true.
 parsers["reader/isFrame()"] = constant(node =>
-  !!node.ownerDocument.defaultView.frameElement);
+  !!node.ownerGlobal.frameElement);
 
 parsers["reader/isEditable()"] = constant(node => {
   const selection = getInputSelection(node);
   return selection ? !node.readOnly && !node.disabled : node.isContentEditable;
 });
 
 
 // TODO: Add some reader to read out tab id.
--- a/addon-sdk/source/lib/framescript/util.js
+++ b/addon-sdk/source/lib/framescript/util.js
@@ -16,10 +16,10 @@ const windowToMessageManager = window =>
     getInterface(Ci.nsIDocShell).
     sameTypeRootTreeItem.
     QueryInterface(Ci.nsIDocShell).
     QueryInterface(Ci.nsIInterfaceRequestor).
     getInterface(Ci.nsIContentFrameMessageManager);
 exports.windowToMessageManager = windowToMessageManager;
 
 const nodeToMessageManager = node =>
-  windowToMessageManager(node.ownerDocument.defaultView);
+  windowToMessageManager(node.ownerGlobal);
 exports.nodeToMessageManager = nodeToMessageManager;
--- a/addon-sdk/source/lib/sdk/addon/window.js
+++ b/addon-sdk/source/lib/sdk/addon/window.js
@@ -46,21 +46,20 @@ docShell.createAboutBlankContentViewer(a
 // such document into that would allow us to create XUL iframes, that
 // are necessary for hidden frames etc..
 var window = docShell.contentViewer.DOMDocument.defaultView;
 window.location = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window/>";
 
 // Create a promise that is delivered once add-on window is interactive,
 // used by add-on runner to defer add-on loading until window is ready.
 var { promise, resolve } = defer();
-eventTarget.addEventListener("DOMContentLoaded", function handler(event) {
-  eventTarget.removeEventListener("DOMContentLoaded", handler, false);
+eventTarget.addEventListener("DOMContentLoaded", function(event) {
   resolve();
-}, false);
+}, {once: true});
 
 exports.ready = promise;
 exports.window = window;
 
 // Still close window on unload to claim memory back early.
 unload(function() {
   window.close()
-  frame.parentNode.removeChild(frame);
+  frame.remove();
 });
--- a/addon-sdk/source/lib/sdk/content/context-menu.js
+++ b/addon-sdk/source/lib/sdk/content/context-menu.js
@@ -127,17 +127,17 @@ var Context = Class({
 
 // Matches when the context-clicked node doesn't have any of
 // NON_PAGE_CONTEXT_ELTS in its ancestors
 CONTEXTS.PageContext = Class({
   extends: Context,
 
   getState: function(popupNode) {
     // If there is a selection in the window then this context does not match
-    if (!popupNode.ownerDocument.defaultView.getSelection().isCollapsed)
+    if (!popupNode.ownerGlobal.getSelection().isCollapsed)
       return false;
 
     // If the clicked node or any of its ancestors is one of the blocked
     // NON_PAGE_CONTEXT_ELTS then this context does not match
     while (!(popupNode instanceof Ci.nsIDOMDocument)) {
       if (NON_PAGE_CONTEXT_ELTS.some(type => popupNode instanceof type))
         return false;
 
@@ -148,17 +148,17 @@ CONTEXTS.PageContext = Class({
   }
 });
 
 // Matches when there is an active selection in the window
 CONTEXTS.SelectionContext = Class({
   extends: Context,
 
   getState: function(popupNode) {
-    if (!popupNode.ownerDocument.defaultView.getSelection().isCollapsed)
+    if (!popupNode.ownerGlobal.getSelection().isCollapsed)
       return true;
 
     try {
       // The node may be a text box which has selectionStart and selectionEnd
       // properties. If not this will throw.
       let { selectionStart, selectionEnd } = popupNode;
       return !isNaN(selectionStart) && !isNaN(selectionEnd) &&
              selectionStart !== selectionEnd;
@@ -206,17 +206,17 @@ CONTEXTS.URLContext = Class({
   }
 });
 
 // Matches when the user-supplied predicate returns true
 CONTEXTS.PredicateContext = Class({
   extends: Context,
 
   getState: function(node) {
-    let window = node.ownerDocument.defaultView;
+    let window = node.ownerGlobal;
     let data = {};
 
     data.documentType = node.ownerDocument.contentType;
 
     data.documentURL = node.ownerDocument.location.href;
     data.targetName = node.nodeName.toLowerCase();
     data.targetID = node.id || null ;
 
@@ -320,17 +320,17 @@ var RemoteItem = Class({
   destroy: function() {
     for (let worker of this.workerMap.values()) {
       worker.destroy();
     }
     keepAlive.delete(this.id);
   },
 
   activate: function(popupNode, data) {
-    let worker = getItemWorkerForWindow(this, popupNode.ownerDocument.defaultView);
+    let worker = getItemWorkerForWindow(this, popupNode.ownerGlobal);
     if (!worker)
       return;
 
     for (let context of this.contexts)
       popupNode = context.adjustPopupNode(popupNode);
 
     worker.fireClick(popupNode, data);
   },
@@ -339,17 +339,17 @@ var RemoteItem = Class({
   getContextState: function(popupNode, addonInfo) {
     if (!(self.id in addonInfo)) {
       addonInfo[self.id] = {
         processID: process.id,
         items: {}
       };
     }
 
-    let worker = getItemWorkerForWindow(this, popupNode.ownerDocument.defaultView);
+    let worker = getItemWorkerForWindow(this, popupNode.ownerGlobal);
     let contextStates = {};
     for (let context of this.contexts)
       contextStates[context.id] = context.getState(popupNode);
 
     addonInfo[self.id].items[this.id] = {
       // It isn't ideal to create a PageContext for every item but there isn't
       // a good shared place to do it.
       pageContext: (new CONTEXTS.PageContext()).getState(popupNode),
--- a/addon-sdk/source/lib/sdk/content/l10n-html.js
+++ b/addon-sdk/source/lib/sdk/content/l10n-html.js
@@ -65,18 +65,17 @@ function translateElement(element) {
 
     translateElementAttributes(child);
   }
 }
 exports.translateElement = translateElement;
 
 function onDocumentReady2Translate(event) {
   let document = event.target;
-  document.removeEventListener("DOMContentLoaded", onDocumentReady2Translate,
-                               false);
+  document.removeEventListener("DOMContentLoaded", onDocumentReady2Translate);
 
   translateElement(document);
 
   try {
     // Finally display document when we finished replacing all text content
     if (document.defaultView)
       removeSheet(document.defaultView, hideSheetUri, 'user');
   }
@@ -103,18 +102,17 @@ function onContentWindow(document) {
     // First hide content of the document in order to have content blinking
     // between untranslated and translated states
     loadSheet(document.defaultView, hideSheetUri, 'user');
   }
   catch(e) {
     console.exception(e);
   }
   // Wait for DOM tree to be built before applying localization
-  document.addEventListener("DOMContentLoaded", onDocumentReady2Translate,
-                            false);
+  document.addEventListener("DOMContentLoaded", onDocumentReady2Translate);
 }
 
 // Listen to creation of content documents in order to translate them as soon
 // as possible in their loading process
 const ON_CONTENT = "document-element-inserted";
 let enabled = false;
 function enable() {
   if (enabled)
--- a/addon-sdk/source/lib/sdk/context-menu.js
+++ b/addon-sdk/source/lib/sdk/context-menu.js
@@ -703,21 +703,21 @@ var MenuWrapper = Class({
     this.populated = false;
     this.menuMap = new Map();
 
     // updateItemVisibilities will run first, updateOverflowState will run after
     // all other instances of this module have run updateItemVisibilities
     this._updateItemVisibilities = this.updateItemVisibilities.bind(this);
     this.contextMenu.addEventListener("popupshowing", this._updateItemVisibilities, true);
     this._updateOverflowState = this.updateOverflowState.bind(this);
-    this.contextMenu.addEventListener("popupshowing", this._updateOverflowState, false);
+    this.contextMenu.addEventListener("popupshowing", this._updateOverflowState);
   },
 
   destroy: function destroy() {
-    this.contextMenu.removeEventListener("popupshowing", this._updateOverflowState, false);
+    this.contextMenu.removeEventListener("popupshowing", this._updateOverflowState);
     this.contextMenu.removeEventListener("popupshowing", this._updateItemVisibilities, true);
 
     if (!this.populated)
       return;
 
     // If we're getting unloaded at runtime then we must remove all the
     // generated XUL nodes
     let oldParent = null;
@@ -877,17 +877,17 @@ var MenuWrapper = Class({
 
       let self = this;
       xulNode.addEventListener("command", function(event) {
         // Only care about clicks directly on this item
         if (event.target !== xulNode)
           return;
 
         itemActivated(item, xulNode);
-      }, false);
+      });
     }
 
     this.insertIntoXUL(item, xulNode, after);
     this.updateXULClass(xulNode);
     xulNode.data = item.data;
 
     if (item instanceof Menu) {
       let menupopup = this.window.document.createElement("menupopup");
@@ -961,24 +961,24 @@ var MenuWrapper = Class({
   onXULRemoved: function onXULRemoved(parent) {
     if (parent == this.contextMenu) {
       let toplevel = this.topLevelItems;
 
       // If there are no more items then remove the separator
       if (toplevel.length == 0) {
         let separator = this.separator;
         if (separator)
-          separator.parentNode.removeChild(separator);
+          separator.remove();
       }
     }
     else if (parent == this.overflowPopup) {
       // If there are no more items then remove the overflow menu and separator
       if (parent.childNodes.length == 0) {
         let separator = this.separator;
-        separator.parentNode.removeChild(separator);
+        separator.remove();
         this.contextMenu.removeChild(parent.parentNode);
       }
     }
   },
 
   // Recurses through all the items owned by this module and sets their hidden
   // state
   updateItemVisibilities: function updateItemVisibilities(event) {
@@ -991,17 +991,17 @@ var MenuWrapper = Class({
       if (internal(this.items).children.length == 0)
         return;
 
       if (!this.populated) {
         this.populated = true;
         this.populate(this.items);
       }
 
-      let mainWindow = event.target.ownerDocument.defaultView;
+      let mainWindow = event.target.ownerGlobal;
       this.contextMenuContentData = mainWindow.gContextMenuContentData
       if (!(self.id in this.contextMenuContentData.addonInfo)) {
         console.warn("No context menu state data was provided.");
         return;
       }
       let addonInfo = this.contextMenuContentData.addonInfo[self.id];
       lastContextProcessId = addonInfo.processID;
       this.setVisibility(this.items, addonInfo.items, true);
--- a/addon-sdk/source/lib/sdk/deprecated/unit-test.js
+++ b/addon-sdk/source/lib/sdk/deprecated/unit-test.js
@@ -312,20 +312,19 @@ TestRunner.prototype = {
 
     let wins = windows(null, { includePrivate: true });
     let winPromises = wins.map(win => {
       return new Promise(resolve => {
         if (["interactive", "complete"].indexOf(win.document.readyState) >= 0) {
           resolve()
         }
         else {
-          win.addEventListener("DOMContentLoaded", function onLoad() {
-            win.removeEventListener("DOMContentLoaded", onLoad, false);
+          win.addEventListener("DOMContentLoaded", function() {
             resolve();
-          }, false);
+          }, {once: true});
         }
       });
     });
 
     PromiseDebugging.flushUncaughtErrors();
     PromiseDebugging.removeUncaughtErrorObserver(this._uncaughtErrorObserver);
 
 
--- a/addon-sdk/source/lib/sdk/dom/events.js
+++ b/addon-sdk/source/lib/sdk/dom/events.js
@@ -152,17 +152,17 @@ function emit(element, type, { category,
   }
 };
 exports.emit = emit;
 
 // Takes DOM `element` and returns promise which is resolved
 // when given element is removed from it's parent node.
 const removed = element => {
   return new Promise(resolve => {
-    const { MutationObserver } = element.ownerDocument.defaultView;
+    const { MutationObserver } = element.ownerGlobal;
     const observer = new MutationObserver(mutations => {
       for (let mutation of mutations) {
         for (let node of mutation.removedNodes || []) {
           if (node === element) {
             observer.disconnect();
             resolve(element);
           }
         }
--- a/addon-sdk/source/lib/sdk/event/dom.js
+++ b/addon-sdk/source/lib/sdk/event/dom.js
@@ -16,17 +16,17 @@ var listeners = new WeakMap();
 
 const { Cu } = require("chrome");
 const { ShimWaiver } = Cu.import("resource://gre/modules/ShimWaiver.jsm");
 const { ThreadSafeChromeUtils } = Cu.import("resource://gre/modules/Services.jsm", {});
 
 var getWindowFrom = x =>
                     x instanceof Ci.nsIDOMWindow ? x :
                     x instanceof Ci.nsIDOMDocument ? x.defaultView :
-                    x instanceof Ci.nsIDOMNode ? x.ownerDocument.defaultView :
+                    x instanceof Ci.nsIDOMNode ? x.ownerGlobal :
                     null;
 
 function removeFromListeners() {
   ShimWaiver.getProperty(this, "removeEventListener")("DOMWindowClose", removeFromListeners);
   for (let cleaner of listeners.get(this))
     cleaner();
 
   listeners.delete(this);
--- a/addon-sdk/source/lib/sdk/frame/hidden-frame.js
+++ b/addon-sdk/source/lib/sdk/frame/hidden-frame.js
@@ -26,20 +26,20 @@ var cache = new Set();
 var elements = new WeakMap();
 
 function contentLoaded(target) {
   var deferred = defer();
   target.addEventListener("DOMContentLoaded", function DOMContentLoaded(event) {
     // "DOMContentLoaded" events from nested frames propagate up to target,
     // ignore events unless it's DOMContentLoaded for the given target.
     if (event.target === target || event.target === target.contentDocument) {
-      target.removeEventListener("DOMContentLoaded", DOMContentLoaded, false);
+      target.removeEventListener("DOMContentLoaded", DOMContentLoaded);
       deferred.resolve(target);
     }
-  }, false);
+  });
   return deferred.promise;
 }
 
 function FrameOptions(options) {
   options = options || {}
   return validateOptions(options, FrameOptions.validator);
 }
 FrameOptions.validator = {
@@ -103,13 +103,13 @@ function removeHiddenFrame(frame) {
     throw Error("The object to be removed must be a HiddenFrame.");
 
   if (!cache.has(frame)) return;
 
   // Remove from cache before calling in order to avoid loop
   cache.delete(frame);
   emit(frame, "unload")
   let element = frame.element
-  if (element) element.parentNode.removeChild(element)
+  if (element) element.remove()
 }
 exports.remove = removeHiddenFrame;
 
 unload(() => fromIterator(cache).forEach(removeHiddenFrame));
--- a/addon-sdk/source/lib/sdk/indexed-db.js
+++ b/addon-sdk/source/lib/sdk/indexed-db.js
@@ -23,19 +23,18 @@ var sanitizeId = function(id){
     replace(uuidRe, "$1");
 
   return domain
 };
 
 const PSEUDOURI = "indexeddb://" + sanitizeId(id) // https://bugzilla.mozilla.org/show_bug.cgi?id=779197
 
 // Use XPCOM because `require("./url").URL` doesn't expose the raw uri object.
-var principaluri = Cc["@mozilla.org/network/io-service;1"].
-              getService(Ci.nsIIOService).
-              newURI(PSEUDOURI, null, null);
+var principaluri = Cc["@mozilla.org/network/io-service;1"]
+                     .getService(Ci.nsIIOService).newURI(PSEUDOURI);
 
 var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
             .getService(Ci.nsIScriptSecurityManager);
 var principal = ssm.createCodebasePrincipal(principaluri, {});
 
 function toArray(args) {
   return Array.prototype.slice.call(args);
 }
--- a/addon-sdk/source/lib/sdk/keyboard/observer.js
+++ b/addon-sdk/source/lib/sdk/keyboard/observer.js
@@ -45,14 +45,13 @@ const Observer = Class({
   /**
    * Function handles all the supported events on all the windows that are
    * observed. Method is used to proxy events to the listeners registered on
    * this event emitter.
    * @param {Event} event
    *    Keyboard event being emitted.
    */
   handleEvent(event) {
-    emit(this, event.type, event, event.target.ownerDocument ? event.target.ownerDocument.defaultView
-                                                             : undefined);
+    emit(this, event.type, event, event.target.ownerGlobal || undefined);
   }
 });
 
 exports.observer = new Observer();
--- a/addon-sdk/source/lib/sdk/panel.js
+++ b/addon-sdk/source/lib/sdk/panel.js
@@ -142,17 +142,17 @@ var SinglePanelManager = {
       SinglePanelManager.notifyPanelCanOpen(panelToOpen, callback);
     }
   },
   notifyPanelCanOpen: function(panel, callback) {
     let view = viewFor(panel);
     // Can't pass an arrow function as the event handler because we need to be
     // able to call |removeEventListener| later.
     view.addEventListener("popuphidden", SinglePanelManager.onVisiblePanelHidden, true);
-    view.addEventListener("popupshown", SinglePanelManager.onVisiblePanelShown, false);
+    view.addEventListener("popupshown", SinglePanelManager.onVisiblePanelShown);
     SinglePanelManager.enqueuedPanel = null;
     SinglePanelManager.enqueuedPanelCallback = null;
     SinglePanelManager.visiblePanel = Cu.getWeakReference(panel);
     callback();
   },
   onVisiblePanelShown: function(event) {
     let panel = panelFor(event.target);
     if (SinglePanelManager.enqueuedPanel) {
@@ -165,17 +165,17 @@ var SinglePanelManager = {
     let view = event.target;
     let panel = panelFor(view);
     let currentPanel = getPanelFromWeakRef(SinglePanelManager.visiblePanel);
     if (currentPanel && currentPanel != panel) {
       return;
     }
     SinglePanelManager.visiblePanel = null;
     view.removeEventListener("popuphidden", SinglePanelManager.onVisiblePanelHidden, true);
-    view.removeEventListener("popupshown", SinglePanelManager.onVisiblePanelShown, false);
+    view.removeEventListener("popupshown", SinglePanelManager.onVisiblePanelShown);
     let nextPanel = getPanelFromWeakRef(SinglePanelManager.enqueuedPanel);
     let nextPanelCallback = SinglePanelManager.enqueuedPanelCallback;
     if (nextPanel) {
       SinglePanelManager.notifyPanelCanOpen(nextPanel, nextPanelCallback);
     }
   }
 };
 
--- a/addon-sdk/source/lib/sdk/panel/utils.js
+++ b/addon-sdk/source/lib/sdk/panel/utils.js
@@ -133,17 +133,17 @@ function display(panel, options, anchor)
     let viewportRect = document.defaultView.gBrowser.getBoundingClientRect();
 
     ({x, y, width, height} = calculateRegion(options, viewportRect));
   }
   else {
     // The XUL Panel has an arrow, so the margin needs to be reset
     // to the default value.
     panel.style.margin = "";
-    let { CustomizableUI, window } = anchor.ownerDocument.defaultView;
+    let { CustomizableUI, window } = anchor.ownerGlobal;
 
     // In Australis, widgets may be positioned in an overflow panel or the
     // menu panel.
     // In such cases clicking this widget will hide the overflow/menu panel,
     // and the widget's panel will show instead.
     // If `CustomizableUI` is not available, it means the anchor is not in a
     // chrome browser window, and therefore there is no need for this check.
     if (CustomizableUI) {
@@ -326,17 +326,17 @@ function make(document, options) {
       events.emit(type, { subject: panel })
   }
 
   panel.addEventListener("popupshowing", onPopupShowing);
   panel.addEventListener("popuphiding", onPopupHiding);
   for (let event of ["popupshowing", "popuphiding", "popupshown", "popuphidden"])
     panel.addEventListener(event, onPanelStateChange);
 
-  panel.addEventListener("click", onPanelClick, false);
+  panel.addEventListener("click", onPanelClick);
 
   // Panel content document can be either in panel `viewFrame` or in
   // a `backgroundFrame` depending on panel state. Listeners are set
   // on both to avoid setting and removing listeners on panel state changes.
 
   panel.addEventListener("DOMContentLoaded", onContentReady, true);
   backgroundFrame.addEventListener("DOMContentLoaded", onContentReady, true);
 
@@ -362,17 +362,17 @@ function attach(panel, document) {
   if (container !== panel.parentNode) {
     detach(panel);
     document.getElementById("mainPopupSet").appendChild(panel);
   }
 }
 exports.attach = attach;
 
 function detach(panel) {
-  if (panel.parentNode) panel.parentNode.removeChild(panel);
+  if (panel.parentNode) panel.remove();
 }
 exports.detach = detach;
 
 function dispose(panel) {
   panel.backgroundFrame.remove();
   panel.backgroundFrame = null;
   events.off("document-element-inserted", panel.onContentChange);
   panel.onContentChange = null;
--- a/addon-sdk/source/lib/sdk/places/events.js
+++ b/addon-sdk/source/lib/sdk/places/events.js
@@ -110,16 +110,30 @@ function formatValue (type, data) {
   if (type === 'type')
     return mapBookmarkItemType(data);
   if (type === 'url' && data)
     return data.spec;
   return data;
 }
 
 var historyObserver = createObserverInstance(HISTORY_EVENTS, HISTORY_ARGS);
+// Hack alert: we sometimes need to send extra title-changed notifications
+// ourselves for backwards compat. Replace the original onVisit callback to
+// add on that logic:
+historyObserver.realOnVisit = historyObserver.onVisit;
+historyObserver.onVisit = function(url, visitId, time, sessionId,
+                                   referringId, transitionType, guid, hidden,
+                                   visitCount, typed, lastKnownTitle) {
+  // If this is the first visit we're adding, fire title-changed
+  // in case anyone cares.
+  if (visitCount == 1) {
+    historyObserver.onTitleChanged(url, lastKnownTitle);
+  }
+  this.realOnVisit(url, visitId, time, sessionId, referringId, transitionType);
+};
 historyService.addObserver(historyObserver, false);
 
 var bookmarkObserver = createObserverInstance(BOOKMARK_EVENTS, BOOKMARK_ARGS);
 bookmarkService.addObserver(bookmarkObserver, false);
 
 when(() => {
   historyService.removeObserver(historyObserver);
   bookmarkService.removeObserver(bookmarkObserver);
--- a/addon-sdk/source/lib/sdk/preferences/event-target.js
+++ b/addon-sdk/source/lib/sdk/preferences/event-target.js
@@ -51,11 +51,11 @@ function onChange(subject, topic, name) 
   }
 }
 
 function destroy() {
   off(this);
 
   // stop listening to preference changes
   let branch = prefTargetNS(this).branch;
-  branch.removeObserver('', prefTargetNS(this).observer, false);
+  branch.removeObserver('', prefTargetNS(this).observer);
   prefTargetNS(this).observer = null;
 }
--- a/addon-sdk/source/lib/sdk/preferences/utils.js
+++ b/addon-sdk/source/lib/sdk/preferences/utils.js
@@ -14,29 +14,28 @@ const { getMostRecentBrowserWindow } = r
 // Opens about:addons in a new tab, then displays the inline
 // preferences of the provided add-on
 const open = ({ id }) => new Promise((resolve, reject) => {
   // opening the about:addons page in a new tab
   let tab = openTab(getMostRecentBrowserWindow(), "about:addons");
   let browser = getBrowserForTab(tab);
 
   // waiting for the about:addons page to load
-  browser.addEventListener("load", function onPageLoad() {
-    browser.removeEventListener("load", onPageLoad, true);
+  browser.addEventListener("load", function() {
     let window = browser.contentWindow;
 
     // wait for the add-on's "addon-options-displayed"
     on("addon-options-displayed", function onPrefDisplayed({ subject: doc, data }) {
       if (data === id) {
         off("addon-options-displayed", onPrefDisplayed);
         resolve({
           id: id,
           tabId: getTabId(tab),
           "document": doc
         });
       }
     }, true);
 
     // display the add-on inline preferences page
     window.gViewController.commands.cmd_showItemDetails.doCommand({ id: id }, true);
-  }, true);
+  }, {capture: true, once: true});
 });
 exports.open = open;
--- a/addon-sdk/source/lib/sdk/remote/child.js
+++ b/addon-sdk/source/lib/sdk/remote/child.js
@@ -127,48 +127,52 @@ function makeFrameEventListener(frame, c
 var FRAME_ID = 0;
 var tabMap = new Map();
 
 const Frame = Class({
   implements: [ Disposable ],
   extends: EventTarget,
   setup: function(contentFrame) {
     // This ID should be unique for this loader across all processes
-    ns(this).id = runtime.processID + ":" + FRAME_ID++;
+    let priv = ns(this);
+
+    priv.id = runtime.processID + ":" + FRAME_ID++;
 
-    ns(this).contentFrame = contentFrame;
-    ns(this).messageManager = contentFrame;
-    ns(this).domListeners = [];
+    priv.contentFrame = contentFrame;
+    priv.messageManager = contentFrame;
+    priv.domListeners = [];
 
     tabMap.set(contentFrame.docShell, this);
 
-    ns(this).messageReceived = messageReceived.bind(this);
-    ns(this).messageManager.addMessageListener('sdk/remote/frame/message', ns(this).messageReceived);
+    priv.messageReceived = messageReceived.bind(this);
+    priv.messageManager.addMessageListener('sdk/remote/frame/message', priv.messageReceived);
 
     this.port = new EventTarget();
     definePort(this, 'sdk/remote/frame/message');
 
-    ns(this).messageManager.sendAsyncMessage('sdk/remote/frame/attach', {
+    priv.messageManager.sendAsyncMessage('sdk/remote/frame/attach', {
       loaderID,
-      frameID: ns(this).id,
+      frameID: priv.id,
       processID: runtime.processID
     });
 
     frames.attachItem(this);
   },
 
   dispose: function() {
+    let priv = ns(this);
+
     emit(this, 'detach', this);
 
-    for (let listener of ns(this).domListeners)
-      ns(this).contentFrame.removeEventListener(...listener.args);
+    for (let listener of priv.domListeners)
+      priv.contentFrame.removeEventListener(...listener.args);
 
-    ns(this).messageManager.removeMessageListener('sdk/remote/frame/message', ns(this).messageReceived);
-    tabMap.delete(ns(this).contentFrame.docShell);
-    ns(this).contentFrame = null;
+    priv.messageManager.removeMessageListener('sdk/remote/frame/message', priv.messageReceived);
+    tabMap.delete(priv.contentFrame.docShell);
+    priv.contentFrame = null;
   },
 
   get content() {
     return ns(this).contentFrame.content;
   },
 
   get isTab() {
     let docShell = ns(this).contentFrame.docShell;
@@ -186,33 +190,37 @@ const Frame = Class({
       // And check we can find a tab for the browser element directly.
       let browser = docShell.chromeEventHandler;
       let tab = require('../tabs/utils').getTabForBrowser(browser);
       return !!tab;
     }
   },
 
   addEventListener: function(...args) {
+    let priv = ns(this);
+
     let listener = listenerFor(...args);
-    if (arrayContainsListener(ns(this).domListeners, listener))
+    if (arrayContainsListener(priv.domListeners, listener))
       return;
 
     listener.registeredCallback = makeFrameEventListener(this, listener.callback);
 
-    ns(this).domListeners.push(listener);
-    ns(this).contentFrame.addEventListener(...listener.args);
+    priv.domListeners.push(listener);
+    priv.contentFrame.addEventListener(...listener.args);
   },
 
   removeEventListener: function(...args) {
-    let listener = getListenerFromArray(ns(this).domListeners, listenerFor(...args));
+    let priv = ns(this);
+
+    let listener = getListenerFromArray(priv.domListeners, listenerFor(...args));
     if (!listener)
       return;
 
-    removeListenerFromArray(ns(this).domListeners, listener);
-    ns(this).contentFrame.removeEventListener(...listener.args);
+    removeListenerFromArray(priv.domListeners, listener);
+    priv.contentFrame.removeEventListener(...listener.args);
   }
 });
 
 const FrameList = Class({
   implements: [ EventParent, Disposable ],
   extends: EventTarget,
   setup: function() {
     EventParent.prototype.initialize.call(this);
@@ -228,22 +236,20 @@ const FrameList = Class({
 
   dispose: function() {
     // The only case where we get destroyed is when the loader is unloaded in
     // which case each frame will clean up its own event listeners.
     ns(this).domListeners = null;
   },
 
   getFrameForWindow: function(window) {
-    for (let frame of this) {
-      if (frame.content == window)
-        return frame;
-    }
+    let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                         .getInterface(Ci.nsIDocShell);
 
-    return null;
+    return tabMap.get(docShell) || null;
   },
 
   addEventListener: function(...args) {
     let listener = listenerFor(...args);
     if (arrayContainsListener(ns(this).domListeners, listener))
       return;
 
     ns(this).domListeners.push(listener);
--- a/addon-sdk/source/lib/sdk/selection.js
+++ b/addon-sdk/source/lib/sdk/selection.js
@@ -140,17 +140,17 @@ function getFocusedWindow() {
  * Returns the focused element in the most recent focused window
  * if private browsing window is most recent and not supported,
  * then ignore it and return `null`, because the focused element
  * can't be targeted.
  */
 function getFocusedElement() {
   let element = winUtils.getFocusedElement();
 
-  if (!element || ignoreWindow(element.ownerDocument.defaultView))
+  if (!element || ignoreWindow(element.ownerGlobal))
     return null;
 
   return element;
 }
 
 /**
  * Returns the current selection from most recent content window. Depending on
  * the specified |type|, the value returned can be a string of text, stringified
--- a/addon-sdk/source/lib/sdk/tab/events.js
+++ b/addon-sdk/source/lib/sdk/tab/events.js
@@ -63,12 +63,12 @@ function makeEvents() {
   // to cover all tab events on all windows that will open.
   return merge([eventsFromInteractive, eventsFromFuture]);
 }
 
 // Map events to Fennec format if necessary
 exports.events = map(makeEvents(), function (event) {
   return !isFennec ? event : {
     type: event.type,
-    target: event.target.ownerDocument.defaultView.BrowserApp
+    target: event.target.ownerGlobal.BrowserApp
             .getTabForBrowser(event.target)
   };
 });
--- a/addon-sdk/source/lib/sdk/tabs/tab-fennec.js
+++ b/addon-sdk/source/lib/sdk/tabs/tab-fennec.js
@@ -31,29 +31,29 @@ const Tab = Class({
     let tabInternals = tabNS(this);
     rawTabNS(tab).tab = this;
 
     let window = tabInternals.window = options.window || getOwnerWindow(tab);
     tabInternals.tab = tab;
 
     // TabReady
     let onReady = tabInternals.onReady = onTabReady.bind(this);
-    tab.browser.addEventListener(EVENTS.ready.dom, onReady, false);
+    tab.browser.addEventListener(EVENTS.ready.dom, onReady);
 
     // TabPageShow
     let onPageShow = tabInternals.onPageShow = onTabPageShow.bind(this);
-    tab.browser.addEventListener(EVENTS.pageshow.dom, onPageShow, false);
+    tab.browser.addEventListener(EVENTS.pageshow.dom, onPageShow);
 
     // TabLoad
     let onLoad = tabInternals.onLoad = onTabLoad.bind(this);
     tab.browser.addEventListener(EVENTS.load.dom, onLoad, true);
 
     // TabClose
     let onClose = tabInternals.onClose = onTabClose.bind(this);
-    window.BrowserApp.deck.addEventListener(EVENTS.close.dom, onClose, false);
+    window.BrowserApp.deck.addEventListener(EVENTS.close.dom, onClose);
 
     unload(cleanupTab.bind(null, this));
   },
 
   /**
    * The title of the page currently loaded in the tab.
    * Changing this property changes an actual title.
    * @type {String}
@@ -186,24 +186,24 @@ exports.Tab = Tab;
 viewFor.define(Tab, x => tabNS(x).tab);
 
 function cleanupTab(tab) {
   let tabInternals = tabNS(tab);
   if (!tabInternals.tab)
     return;
 
   if (tabInternals.tab.browser) {
-    tabInternals.tab.browser.removeEventListener(EVENTS.ready.dom, tabInternals.onReady, false);
-    tabInternals.tab.browser.removeEventListener(EVENTS.pageshow.dom, tabInternals.onPageShow, false);
+    tabInternals.tab.browser.removeEventListener(EVENTS.ready.dom, tabInternals.onReady);
+    tabInternals.tab.browser.removeEventListener(EVENTS.pageshow.dom, tabInternals.onPageShow);
     tabInternals.tab.browser.removeEventListener(EVENTS.load.dom, tabInternals.onLoad, true);
   }
   tabInternals.onReady = null;
   tabInternals.onPageShow = null;
   tabInternals.onLoad = null;
-  tabInternals.window.BrowserApp.deck.removeEventListener(EVENTS.close.dom, tabInternals.onClose, false);
+  tabInternals.window.BrowserApp.deck.removeEventListener(EVENTS.close.dom, tabInternals.onClose);
   tabInternals.onClose = null;
   rawTabNS(tabInternals.tab).tab = null;
   tabInternals.tab = null;
   tabInternals.window = null;
 }
 
 function onTabReady(event) {
   let win = event.target.defaultView;
--- a/addon-sdk/source/lib/sdk/tabs/tab-firefox.js
+++ b/addon-sdk/source/lib/sdk/tabs/tab-firefox.js
@@ -62,17 +62,17 @@ const Tab = Class({
       // Note that activate is defered and so will run after any open event
       // is sent out
       if (!options.inBackground)
         this.activate();
     }
 
     getURL.implement(this, tab => tab.url);
     isPrivate.implement(this, tab => {
-      return isWindowPrivate(viewsFor.get(tab).ownerDocument.defaultView);
+      return isWindowPrivate(viewsFor.get(tab).ownerGlobal);
     });
   },
 
   get id() {
     return isDestroyed(this) ? undefined : getTabId(viewsFor.get(this));
   },
 
   get title() {
@@ -118,17 +118,17 @@ const Tab = Class({
 
   get window() {
     if (isClosed(this))
       return undefined;
 
     // TODO: Remove the dependency on the windows module, see bug 792670
     require('../windows');
     let tabElement = viewsFor.get(this);
-    let domWindow = tabElement.ownerDocument.defaultView;
+    let domWindow = tabElement.ownerGlobal;
     return modelFor(domWindow);
   },
 
   get readyState() {
     return isDestroyed(this) ? undefined : this[remoteReadyStateCached] || "uninitialized";
   },
 
   pin: function() {
@@ -251,17 +251,17 @@ function maybeWindowFor(domWindow) {
 function tabEmit(tab, event, ...args) {
   // Don't emit events for destroyed tabs
   if (isDestroyed(tab))
     return;
 
   // If the windows module was never loaded this will return null. We don't need
   // to emit to the window.tabs object in this case as nothing can be listening.
   let tabElement = viewsFor.get(tab);
-  let window = maybeWindowFor(tabElement.ownerDocument.defaultView);
+  let window = maybeWindowFor(tabElement.ownerGlobal);
   if (window)
     emit(window.tabs, event, tab, ...args);
 
   emit(tabEvents, event, tab, ...args);
   emit(tab, event, tab, ...args);
 }
 
 function windowClosed(domWindow) {
@@ -276,17 +276,17 @@ windowObserver.on('close', windowClosed)
 
 // Don't want to send close events after unloaded
 when(_ => {
   windowObserver.off('close', windowClosed);
 });
 
 // Listen for tabbrowser events
 function tabEventListener(event, tabElement, ...args) {
-  let domWindow = tabElement.ownerDocument.defaultView;
+  let domWindow = tabElement.ownerGlobal;
 
   if (ignoreWindow(domWindow))
     return;
 
   // Don't send events for tabs that are already closing
   if (event != "close" && (tabElement.closing || !tabElement.parentNode))
     return;
 
--- a/addon-sdk/source/lib/sdk/tabs/utils.js
+++ b/addon-sdk/source/lib/sdk/tabs/utils.js
@@ -101,17 +101,17 @@ exports.getTabs = getTabs;
 function getActiveTab(window) {
   return getSelectedTab(window);
 }
 exports.getActiveTab = getActiveTab;
 
 function getOwnerWindow(tab) {
   // normal case
   if (tab.ownerDocument)
-    return tab.ownerDocument.defaultView;
+    return tab.ownerGlobal;
 
   // try fennec case
   return getWindowHoldingTab(tab);
 }
 exports.getOwnerWindow = getOwnerWindow;
 
 // fennec
 function getWindowHoldingTab(rawTab) {
--- a/addon-sdk/source/lib/sdk/test/harness.js
+++ b/addon-sdk/source/lib/sdk/test/harness.js
@@ -275,17 +275,17 @@ function getPotentialLeaks() {
     "resource://pdf.js.components/",
     "resource://services-common/",
     "resource://services-crypto/",
     "resource://services-sync/"
   ];
 
   let ioService = Cc["@mozilla.org/network/io-service;1"].
                  getService(Ci.nsIIOService);
-  let uri = ioService.newURI("chrome://global/content/", "UTF-8", null);
+  let uri = ioService.newURI("chrome://global/content/", "UTF-8");
   let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
                   getService(Ci.nsIChromeRegistry);
   uri = chromeReg.convertChromeURL(uri);
   let spec = uri.spec;
   let pos = spec.indexOf("!/");
   GOOD_BASE_URLS.push(spec.substring(0, pos + 2));
 
   let zoneRegExp = new RegExp("^explicit/js-non-window/zones/zone[^/]+/compartment\\((.+)\\)");
--- a/addon-sdk/source/lib/sdk/ui/button/view.js
+++ b/addon-sdk/source/lib/sdk/ui/button/view.js
@@ -46,17 +46,17 @@ const buttonListener = {
 
       if (placement)
         emit(viewEvents, 'data', { type: 'update', target: id, window: window });
     }
   },
   onWidgetAfterDOMChange: (node, nextNode, container) => {
     let { id } = node;
     let view = views.get(id);
-    let window = node.ownerDocument.defaultView;
+    let window = node.ownerGlobal;
 
     if (view) {
       emit(viewEvents, 'data', { type: 'update', target: id, window: window });
     }
   }
 };
 
 CustomizableUI.addListener(buttonListener);
--- a/addon-sdk/source/lib/sdk/ui/frame/view.js
+++ b/addon-sdk/source/lib/sdk/ui/frame/view.js
@@ -69,34 +69,32 @@ const registerFrame = ({id, url}) => {
       outerFrame.setAttribute("data-is-sdk-outer-frame", true);
       outerFrame.setAttribute("type", "content");
       outerFrame.setAttribute("transparent", true);
       outerFrame.setAttribute("flex", 2);
       outerFrame.setAttribute("style", "overflow: hidden;");
       outerFrame.setAttribute("scrolling", "no");
       outerFrame.setAttribute("disablehistory", true);
       outerFrame.setAttribute("seamless", "seamless");
-      outerFrame.addEventListener("load", function onload() {
-        outerFrame.removeEventListener("load", onload, true);
-
+      outerFrame.addEventListener("load", function() {
         let doc = outerFrame.contentDocument;
 
         let innerFrame = doc.createElementNS(HTML_NS, "iframe");
         innerFrame.setAttribute("id", id);
         innerFrame.setAttribute("src", url);
         innerFrame.setAttribute("seamless", "seamless");
         innerFrame.setAttribute("sandbox", "allow-scripts");
         innerFrame.setAttribute("scrolling", "no");
         innerFrame.setAttribute("data-is-sdk-inner-frame", true);
         innerFrame.setAttribute("style", [ "border:none",
           "position:absolute", "width:100%", "top: 0",
           "left: 0", "overflow: hidden"].join(";"));
 
         doc.body.appendChild(innerFrame);
-      }, true);
+      }, {capture: true, once: true});
 
       view.appendChild(outerFrame);
 
       return view;
     }
   });
 };
 
--- a/addon-sdk/source/lib/sdk/ui/sidebar.js
+++ b/addon-sdk/source/lib/sdk/ui/sidebar.js
@@ -87,17 +87,17 @@ const Sidebar = Class({
 
         bar.addEventListener('command', function() {
           if (isSidebarShowing(window, self)) {
             hideSidebar(window, self).catch(() => {});
             return;
           }
 
           showSidebar(window, self);
-        }, false);
+        });
 
         function onSidebarLoad() {
           // check if the sidebar is ready
           let isReady = sidebar.docShell && sidebar.contentDocument;
           if (!isReady)
             return;
 
           // check if it is a web panel
@@ -131,23 +131,23 @@ const Sidebar = Class({
             }
             windowNS(window).onWebPanelSidebarUnload = onWebPanelSidebarUnload;
             panelBrowser.contentWindow.addEventListener('unload', onWebPanelSidebarUnload, true);
 
             // check the associated menuitem
             bar.setAttribute('checked', 'true');
 
             function onWebPanelSidebarReady() {
-              panelBrowser.contentWindow.removeEventListener('DOMContentLoaded', onWebPanelSidebarReady, false);
+              panelBrowser.contentWindow.removeEventListener('DOMContentLoaded', onWebPanelSidebarReady);
               windowNS(window).onWebPanelSidebarReady = null;
 
               emit(self, 'ready', worker);
             }
             windowNS(window).onWebPanelSidebarReady = onWebPanelSidebarReady;
-            panelBrowser.contentWindow.addEventListener('DOMContentLoaded', onWebPanelSidebarReady, false);
+            panelBrowser.contentWindow.addEventListener('DOMContentLoaded', onWebPanelSidebarReady);
 
             function onWebPanelSidebarLoad() {
               panelBrowser.contentWindow.removeEventListener('load', onWebPanelSidebarLoad, true);
               windowNS(window).onWebPanelSidebarLoad = null;
 
               // TODO: decide if returning worker is acceptable..
               //emit(self, 'show', { worker: worker });
               emit(self, 'show', {});
@@ -187,17 +187,17 @@ const Sidebar = Class({
 
         let panelBrowser = sidebar && sidebar.contentDocument.getElementById(WEB_PANEL_BROWSER_ID);
         if (windowNS(window).onWebPanelSidebarCreated) {
           panelBrowser && panelBrowser.removeEventListener('DOMWindowCreated', windowNS(window).onWebPanelSidebarCreated, true);
           windowNS(window).onWebPanelSidebarCreated = null;
         }
 
         if (windowNS(window).onWebPanelSidebarReady) {
-          panelBrowser && panelBrowser.contentWindow.removeEventListener('DOMContentLoaded', windowNS(window).onWebPanelSidebarReady, false);
+          panelBrowser && panelBrowser.contentWindow.removeEventListener('DOMContentLoaded', windowNS(window).onWebPanelSidebarReady);
           windowNS(window).onWebPanelSidebarReady = null;
         }
 
         if (windowNS(window).onWebPanelSidebarLoad) {
           panelBrowser && panelBrowser.contentWindow.removeEventListener('load', windowNS(window).onWebPanelSidebarLoad, true);
           windowNS(window).onWebPanelSidebarLoad = null;
         }
 
--- a/addon-sdk/source/lib/sdk/ui/sidebar/view.js
+++ b/addon-sdk/source/lib/sdk/ui/sidebar/view.js
@@ -39,17 +39,17 @@ function create(window, details) {
 
   document.getElementById('viewSidebarMenu').appendChild(menuitem);
 
   return menuitem;
 }
 exports.create = create;
 
 function dispose(menuitem) {
-  menuitem.parentNode.removeChild(menuitem);
+  menuitem.remove();
 }
 exports.dispose = dispose;
 
 function updateTitle(sidebar, title) {
   let button = buttons.get(sidebar);
 
   for (let window of windows(null, { includePrivate: true })) {
   	let { document } = window;
--- a/addon-sdk/source/lib/sdk/ui/toolbar/view.js
+++ b/addon-sdk/source/lib/sdk/ui/toolbar/view.js
@@ -120,17 +120,17 @@ const addView = curry((options, {documen
   // a toolbar inside a toolbar.
   // This is should be a temporary hack, we should have a proper XBL for toolbar
   // instead. See:
   // https://bugzilla.mozilla.org/show_bug.cgi?id=982005
   let toolbar = document.createElementNS(XUL_NS, "toolbar");
   toolbar.setAttribute("id", "inner-" + options.id);
   toolbar.setAttribute("defaultset", options.items.join(","));
   toolbar.setAttribute("customizable", "true");
-  toolbar.setAttribute("style", "-moz-appearance: none; overflow: hidden");
+  toolbar.setAttribute("style", "-moz-appearance: none; overflow: hidden; border: 0;");
   toolbar.setAttribute("mode", "icons");
   toolbar.setAttribute("iconsize", "small");
   toolbar.setAttribute("context", "toolbar-context-menu");
   toolbar.setAttribute("flex", "1");
 
   view.insertBefore(toolbar, closeButton);
 
   const observer = new document.defaultView.MutationObserver(attributesChanged);
--- a/addon-sdk/source/lib/sdk/uri/resource.js
+++ b/addon-sdk/source/lib/sdk/uri/resource.js
@@ -12,17 +12,17 @@ const ioService = Cc["@mozilla.org/netwo
                   getService(Ci.nsIIOService);
 const resourceHandler = ioService.getProtocolHandler("resource").
                         QueryInterface(Ci.nsIResProtocolHandler);
 
 const URI = (uri, base=null) =>
   ioService.newURI(uri, null, base && URI(base))
 
 const mount = (domain, uri) =>
-  resourceHandler.setSubstitution(domain, ioService.newURI(uri, null, null));
+  resourceHandler.setSubstitution(domain, ioService.newURI(uri));
 exports.mount = mount;
 
 const unmount = (domain, uri) =>
   resourceHandler.setSubstitution(domain, null);
 exports.unmount = unmount;
 
 const domain = 1;
 const path = 2;
--- a/addon-sdk/source/lib/sdk/url.js
+++ b/addon-sdk/source/lib/sdk/url.js
@@ -22,17 +22,17 @@ var resProt = ios.getProtocolHandler("re
 
 var URLParser = Cc["@mozilla.org/network/url-parser;1?auth=no"]
                 .getService(Ci.nsIURLParser);
 
 const { Services } = Cu.import("resource://gre/modules/Services.jsm");
 
 function newURI(uriStr, base) {
   try {
-    let baseURI = base ? ios.newURI(base, null, null) : null;
+    let baseURI = base ? ios.newURI(base) : null;
     return ios.newURI(uriStr, null, baseURI);
   }
   catch (e) {
     if (e.result == Cr.NS_ERROR_MALFORMED_URI) {
       throw new Error("malformed URI: " + uriStr);
     }
     if (e.result == Cr.NS_ERROR_FAILURE ||
         e.result == Cr.NS_ERROR_ILLEGAL_VALUE) {
--- a/addon-sdk/source/lib/sdk/url/utils.js
+++ b/addon-sdk/source/lib/sdk/url/utils.js
@@ -12,17 +12,17 @@ const { Cc, Ci, Cr } = require("chrome")
 const IOService = Cc["@mozilla.org/network/io-service;1"].
                     getService(Ci.nsIIOService);
 const { isValidURI } = require("../url");
 const { method } = require("../../method/core");
 
 function newURI (uri) {
   if (!isValidURI(uri))
     throw new Error("malformed URI: " + uri);
-  return IOService.newURI(uri, null, null);
+  return IOService.newURI(uri);
 }
 exports.newURI = newURI;
 
 var getURL = method('sdk/url:getURL');
 getURL.define(String, url => url);
 getURL.define(function (object) {
   return null;
 });
--- a/addon-sdk/source/lib/sdk/window/helpers.js
+++ b/addon-sdk/source/lib/sdk/window/helpers.js
@@ -66,16 +66,15 @@ function startup(window) {
   return result;
 }
 exports.startup = startup;
 
 function promise(target, evt, capture) {
   let deferred = defer();
   capture = !!capture;
 
-  target.addEventListener(evt, function eventHandler() {
-    target.removeEventListener(evt, eventHandler, capture);
+  target.addEventListener(evt, function() {
     deferred.resolve(target);
-  }, capture);
+  }, {capture, once: true});
 
   return deferred.promise;
 }
 exports.promise = promise;
--- a/addon-sdk/source/lib/sdk/window/utils.js
+++ b/addon-sdk/source/lib/sdk/window/utils.js
@@ -187,17 +187,17 @@ function serializeFeatures(options) {
  */
 function open(uri, options) {
   uri = uri || URI_BROWSER;
   options = options || {};
 
   if (!uri)
     throw new Error('browser.chromeURL is undefined, please provide an explicit uri');
 
-  if (['chrome', 'resource', 'data'].indexOf(io.newURI(uri, null, null).scheme) < 0)
+  if (['chrome', 'resource', 'data'].indexOf(io.newURI(uri).scheme) < 0)
     throw new Error('only chrome, resource and data uris are allowed');
 
   let newWindow = windowWatcher.
     openWindow(options.parent || null,
                uri,
                options.name || null,
                options.features ? serializeFeatures(options.features) : null,
                options.args || null);
@@ -208,20 +208,19 @@ exports.open = open;
 
 function onFocus(window) {
   let { resolve, promise } = defer();
 
   if (isFocused(window)) {
     resolve(window);
   }
   else {
-    window.addEventListener("focus", function focusListener() {
-      window.removeEventListener("focus", focusListener, true);
+    window.addEventListener("focus", function() {
       resolve(window);
-    }, true);
+    }, {capture: true, once: true});
   }
 
   return promise;
 }
 exports.onFocus = onFocus;
 
 var isFocused = dispatcher("window-isFocused");
 isFocused.when(x => x instanceof Ci.nsIDOMWindow, (window) => {
@@ -411,17 +410,17 @@ function getScreenPixelsPerCSSPixel(wind
                 getInterface(Ci.nsIDOMWindowUtils).screenPixelsPerCSSPixel;
 }
 exports.getScreenPixelsPerCSSPixel = getScreenPixelsPerCSSPixel;
 
 function getOwnerBrowserWindow(node) {
   /**
   Takes DOM node and returns browser window that contains it.
   **/
-  let window = getToplevelWindow(node.ownerDocument.defaultView);
+  let window = getToplevelWindow(node.ownerGlobal);
   // If anchored window is browser then it's target browser window.
   return isBrowser(window) ? window : null;
 }
 exports.getOwnerBrowserWindow = getOwnerBrowserWindow;
 
 function getParentWindow(window) {
   try {
     return window.QueryInterface(Ci.nsIInterfaceRequestor)
--- a/addon-sdk/source/lib/sdk/windows/tabs-fennec.js
+++ b/addon-sdk/source/lib/sdk/windows/tabs-fennec.js
@@ -34,20 +34,20 @@ const Tabs = Class({
   initialize: function initialize(options) {
     let tabsInternals = tabsNS(this);
     let window = tabsNS(this).window = options.window || mainWindow;
 
     EventTarget.prototype.initialize.call(this, options);
     List.prototype.initialize.apply(this, getTabs(window).map(Tab));
 
     // TabOpen event
-    window.BrowserApp.deck.addEventListener(EVENTS.open.dom, onTabOpen, false);
+    window.BrowserApp.deck.addEventListener(EVENTS.open.dom, onTabOpen);
 
     // TabSelect
-    window.BrowserApp.deck.addEventListener(EVENTS.activate.dom, onTabSelect, false);
+    window.BrowserApp.deck.addEventListener(EVENTS.activate.dom, onTabSelect);
   },
   get activeTab() {
     return getTabForRawTab(getSelectedTab(tabsNS(this).window));
   },
   open: function(options) {
     options = Options(options);
     let activeWin = browserWindows.activeWindow;
 
@@ -91,18 +91,18 @@ const Tabs = Class({
   }
 });
 var gTabs = exports.tabs = Tabs(mainWindow);
 
 function tabsUnloader(event, window) {
   window = window || (event && event.target);
   if (!(window && window.BrowserApp))
     return;
-  window.BrowserApp.deck.removeEventListener(EVENTS.open.dom, onTabOpen, false);
-  window.BrowserApp.deck.removeEventListener(EVENTS.activate.dom, onTabSelect, false);
+  window.BrowserApp.deck.removeEventListener(EVENTS.open.dom, onTabOpen);
+  window.BrowserApp.deck.removeEventListener(EVENTS.activate.dom, onTabSelect);
 }
 
 // unload handler
 unload(function() {
   for (let window in windowIterator()) {
     tabsUnloader(null, window);
   }
 });
--- a/addon-sdk/source/python-lib/cuddlefish/prefs.py
+++ b/addon-sdk/source/python-lib/cuddlefish/prefs.py
@@ -18,17 +18,17 @@ DEFAULT_COMMON_PREFS = {
     'extensions.checkCompatibility.nightly' : False,
 
     # Disable extension updates and notifications.
     'extensions.update.enabled' : False,
     'lightweightThemes.update.enabled' : False,
     'extensions.update.notifyUser' : False,
 
     # From:
-    # http://hg.mozilla.org/mozilla-central/file/1dd81c324ac7/build/automation.py.in#l372
+    # https://hg.mozilla.org/mozilla-central/file/1dd81c324ac7/build/automation.py.in#l372
     # Only load extensions from the application and user profile.
     # AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
     'extensions.enabledScopes' : 5,
     # Disable metadata caching for installed add-ons by default
     'extensions.getAddons.cache.enabled' : False,
     # Disable intalling any distribution add-ons
     'extensions.installDistroAddons' : False,
     # Allow installing extensions dropped into the profile folder
@@ -53,16 +53,18 @@ DEFAULT_NO_CONNECTIONS_PREFS = {
     'media.gmp-manager.updateEnabled': False,
     'browser.aboutHomeSnippets.updateUrl': 'https://localhost/snippet-dummy',
     'browser.newtab.url' : 'about:blank',
     'browser.search.update': False,
     'browser.search.suggest.enabled' : False,
     'browser.safebrowsing.phishing.enabled' : False,
     'browser.safebrowsing.provider.google.updateURL': 'http://localhost/safebrowsing-dummy/update',
     'browser.safebrowsing.provider.google.gethashURL': 'http://localhost/safebrowsing-dummy/gethash',
+    'browser.safebrowsing.provider.google4.updateURL': 'http://localhost/safebrowsing4-dummy/update',
+    'browser.safebrowsing.provider.google4.gethashURL': 'http://localhost/safebrowsing4-dummy/gethash',
     'browser.safebrowsing.malware.reportURL': 'http://localhost/safebrowsing-dummy/malwarereport',
     'browser.selfsupport.url': 'https://localhost/selfsupport-dummy',
     'browser.safebrowsing.provider.mozilla.gethashURL': 'http://localhost/safebrowsing-dummy/gethash',
     'browser.safebrowsing.provider.mozilla.updateURL': 'http://localhost/safebrowsing-dummy/update',
 
     # Disable app update
     'app.update.enabled' : False,
     'app.update.staging.enabled': False,
@@ -108,22 +110,24 @@ DEFAULT_FENNEC_PREFS = {
 # When launching a temporary new Firefox profile, use these preferences.
 DEFAULT_FIREFOX_PREFS = {
     'browser.startup.homepage' : 'about:blank',
     'startup.homepage_welcome_url' : 'about:blank',
     'devtools.browsertoolbox.panel': 'jsdebugger',
     'devtools.chrome.enabled' : True,
 
     # From:
-    # http://hg.mozilla.org/mozilla-central/file/1dd81c324ac7/build/automation.py.in#l388
+    # https://hg.mozilla.org/mozilla-central/file/1dd81c324ac7/build/automation.py.in#l388
     # Make url-classifier updates so rare that they won't affect tests.
     'urlclassifier.updateinterval' : 172800,
     # Point the url-classifier to a nonexistent local URL for fast failures.
     'browser.safebrowsing.provider.google.gethashURL' : 'http://localhost/safebrowsing-dummy/gethash',
     'browser.safebrowsing.provider.google.updateURL' : 'http://localhost/safebrowsing-dummy/update',
+    'browser.safebrowsing.provider.google4.gethashURL' : 'http://localhost/safebrowsing4-dummy/gethash',
+    'browser.safebrowsing.provider.google4.updateURL' : 'http://localhost/safebrowsing4-dummy/update',
     'browser.safebrowsing.provider.mozilla.gethashURL': 'http://localhost/safebrowsing-dummy/gethash',
     'browser.safebrowsing.provider.mozilla.updateURL': 'http://localhost/safebrowsing-dummy/update',
 }
 
 # When launching a temporary new Thunderbird profile, use these preferences.
 # Note that these were taken from:
 # http://dxr.mozilla.org/comm-central/source/mail/test/mozmill/runtest.py
 DEFAULT_THUNDERBIRD_PREFS = {
@@ -207,17 +211,16 @@ DEFAULT_TEST_PREFS = {
     'security.default_personal_cert': 'Select Automatically',
     'network.http.prompt-temp-redirect': False,
     'security.warn_viewing_mixed': False,
     'extensions.defaultProviders.enabled': True,
     'datareporting.policy.dataSubmissionPolicyBypassNotification': True,
     'layout.css.report_errors': True,
     'layout.css.grid.enabled': True,
     'layout.spammy_warnings.enabled': False,
-    'dom.mozSettings.enabled': True,
     # Make sure the disk cache doesn't get auto disabled
     'network.http.bypass-cachelock-threshold': 200000,
     # Always use network provider for geolocation tests
     # so we bypass the OSX dialog raised by the corelocation provider
     'geo.provider.testing': True,
     # Background thumbnails in particular cause grief, and disabling thumbnails
     # in general can't hurt - we re-enable them when tests need them.
     'browser.pagethumbnails.capturing_disabled': True,
@@ -225,15 +228,14 @@ DEFAULT_TEST_PREFS = {
     # download test runs first doesn't show the popup inconsistently.
     'browser.download.panel.shown': True,
     # Assume the about:newtab page's intro panels have been shown to not depend on
     # which test runs first and happens to open about:newtab
     'browser.newtabpage.introShown': True,
     # Disable useragent updates.
     'general.useragent.updates.enabled': False,
     'media.eme.enabled': True,
-    'media.eme.apiVisible': True,
-    # Don't forceably kill content processes after a timeout
+    # Don't forcibly kill content processes after a timeout
     'dom.ipc.tabs.shutdownTimeoutSecs': 0,
     'general.useragent.locale': "en-US",
     'intl.locale.matchOS': "en-US",
     'dom.indexedDB.experimental': True
 }
--- a/addon-sdk/source/test/addons/content-permissions/httpd.js
+++ b/addon-sdk/source/test/addons/content-permissions/httpd.js
@@ -1641,17 +1641,17 @@ RequestReader.prototype =
       // No absolute paths in the request line in HTTP prior to 1.1
       if (!metadata._httpVersion.atLeast(nsHttpVersion.HTTP_1_1))
         throw HTTP_400;
 
       try
       {
         var uri = Cc["@mozilla.org/network/io-service;1"]
                     .getService(Ci.nsIIOService)
-                    .newURI(fullPath, null, null);
+                    .newURI(fullPath);
         fullPath = uri.path;
         scheme = uri.scheme;
         host = metadata._host = uri.asciiHost;
         port = uri.port;
         if (port === -1)
         {
           if (scheme === "http")
             port = 80;
@@ -4792,17 +4792,17 @@ nsHttpHeaders.prototype =
 */
   setHeader: function(fieldName, fieldValue, merge)
   {
     var name = headerUtils.normalizeFieldName(fieldName);
     var value = headerUtils.normalizeFieldValue(fieldValue);
 
     // The following three headers are stored as arrays because their real-world
     // syntax prevents joining individual headers into a single header using
-    // ",". See also <http://hg.mozilla.org/mozilla-central/diff/9b2a99adc05e/netwerk/protocol/http/src/nsHttpHeaderArray.cpp#l77>
+    // ",". See also <https://hg.mozilla.org/mozilla-central/diff/9b2a99adc05e/netwerk/protocol/http/src/nsHttpHeaderArray.cpp#l77>
     if (merge && name in this._headers)
     {
       if (name === "www-authenticate" ||
           name === "proxy-authenticate" ||
           name === "set-cookie")
       {
         this._headers[name].push(value);
       }
--- a/addon-sdk/source/test/addons/content-permissions/main.js
+++ b/addon-sdk/source/test/addons/content-permissions/main.js
@@ -16,20 +16,19 @@ exports.testCrossDomainIframe = function
     response.write("<html><body>foo</body></html>");
   });
 
   let pageMod = PageMod({
     include: TEST_TAB_URL,
     contentScript: "new " + function ContentScriptScope() {
       self.on("message", function (url) {
         let iframe = document.createElement("iframe");
-        iframe.addEventListener("load", function onload() {
-          iframe.removeEventListener("load", onload, false);
+        iframe.addEventListener("load", function() {
           self.postMessage(iframe.contentWindow.document.body.innerHTML);
-        }, false);
+        }, {once: true});
         iframe.setAttribute("src", url);
         document.documentElement.appendChild(iframe);
       });
     },
     onAttach: function(w) {
       w.on("message", function (body) {
         assert.equal(body, "foo", "received iframe html content");
         pageMod.destroy();
--- a/addon-sdk/source/test/addons/content-script-messages-latency/httpd.js
+++ b/addon-sdk/source/test/addons/content-script-messages-latency/httpd.js
@@ -1641,17 +1641,17 @@ RequestReader.prototype =
       // No absolute paths in the request line in HTTP prior to 1.1
       if (!metadata._httpVersion.atLeast(nsHttpVersion.HTTP_1_1))
         throw HTTP_400;
 
       try
       {
         var uri = Cc["@mozilla.org/network/io-service;1"]
                     .getService(Ci.nsIIOService)
-                    .newURI(fullPath, null, null);
+                    .newURI(fullPath);
         fullPath = uri.path;
         scheme = uri.scheme;
         host = metadata._host = uri.asciiHost;
         port = uri.port;
         if (port === -1)
         {
           if (scheme === "http")
             port = 80;
@@ -4792,17 +4792,17 @@ nsHttpHeaders.prototype =
 */
   setHeader: function(fieldName, fieldValue, merge)
   {
     var name = headerUtils.normalizeFieldName(fieldName);
     var value = headerUtils.normalizeFieldValue(fieldValue);
 
     // The following three headers are stored as arrays because their real-world
     // syntax prevents joining individual headers into a single header using
-    // ",". See also <http://hg.mozilla.org/mozilla-central/diff/9b2a99adc05e/netwerk/protocol/http/src/nsHttpHeaderArray.cpp#l77>
+    // ",". See also <https://hg.mozilla.org/mozilla-central/diff/9b2a99adc05e/netwerk/protocol/http/src/nsHttpHeaderArray.cpp#l77>
     if (merge && name in this._headers)
     {
       if (name === "www-authenticate" ||
           name === "proxy-authenticate" ||
           name === "set-cookie")
       {
         this._headers[name].push(value);
       }
--- a/addon-sdk/source/test/addons/e10s-content/lib/httpd.js
+++ b/addon-sdk/source/test/addons/e10s-content/lib/httpd.js
@@ -1642,17 +1642,17 @@ RequestReader.prototype =
       // No absolute paths in the request line in HTTP prior to 1.1
       if (!metadata._httpVersion.atLeast(nsHttpVersion.HTTP_1_1))
         throw HTTP_400;
 
       try
       {
         var uri = Cc["@mozilla.org/network/io-service;1"]
                     .getService(Ci.nsIIOService)
-                    .newURI(fullPath, null, null);
+                    .newURI(fullPath);
         fullPath = uri.path;
         scheme = uri.scheme;
         host = metadata._host = uri.asciiHost;
         port = uri.port;
         if (port === -1)
         {
           if (scheme === "http")
             port = 80;
@@ -4793,17 +4793,17 @@ nsHttpHeaders.prototype =
 */
   setHeader: function(fieldName, fieldValue, merge)
   {
     var name = headerUtils.normalizeFieldName(fieldName);
     var value = headerUtils.normalizeFieldValue(fieldValue);
 
     // The following three headers are stored as arrays because their real-world
     // syntax prevents joining individual headers into a single header using
-    // ",". See also <http://hg.mozilla.org/mozilla-central/diff/9b2a99adc05e/netwerk/protocol/http/src/nsHttpHeaderArray.cpp#l77>
+    // ",". See also <https://hg.mozilla.org/mozilla-central/diff/9b2a99adc05e/netwerk/protocol/http/src/nsHttpHeaderArray.cpp#l77>
     if (merge && name in this._headers)
     {
       if (name === "www-authenticate" ||
           name === "proxy-authenticate" ||
           name === "set-cookie")
       {
         this._headers[name].push(value);
       }
--- a/addon-sdk/source/test/addons/e10s-content/lib/test-content-script.js
+++ b/addon-sdk/source/test/addons/e10s-content/lib/test-content-script.js
@@ -23,44 +23,43 @@ function createProxyTest(html, callback)
       nodeName: "iframe",
       type: "content",
       allowJavascript: true,
       allowPlugins: true,
       allowAuth: true,
       uri: testURI
     });
 
-    element.addEventListener("DOMContentLoaded", onDOMReady, false);
+    element.addEventListener("DOMContentLoaded", onDOMReady);
 
     function onDOMReady() {
       // Reload frame after getting principal from `testURI`
       if (!principalLoaded) {
         element.setAttribute("src", url);
         principalLoaded = true;
         return;
       }
 
       assert.equal(element.getAttribute("src"), url, "correct URL loaded");
-      element.removeEventListener("DOMContentLoaded", onDOMReady,
-                                                  false);
+      element.removeEventListener("DOMContentLoaded", onDOMReady);
       let xrayWindow = element.contentWindow;
       let rawWindow = xrayWindow.wrappedJSObject;
 
       let isDone = false;
       let helper = {
         xrayWindow: xrayWindow,
         rawWindow: rawWindow,
         createWorker: function (contentScript) {
           return createWorker(assert, xrayWindow, contentScript, helper.done);
         },
         done: function () {
           if (isDone)
             return;
           isDone = true;
-          element.parentNode.removeChild(element);
+          element.remove();
           done();
         }
       };
       callback(helper, assert);
     }
   };
 }
 
@@ -169,31 +168,30 @@ exports["test Shared To String Proxies"]
 */
 
 // Ensure that postMessage is working correctly across documents with an iframe
 var html = '<iframe id="iframe" name="test" src="data:text/html;charset=utf-8," />';
 exports["test postMessage"] = createProxyTest(html, function (helper, assert) {
   let ifWindow = helper.xrayWindow.document.getElementById("iframe").contentWindow;
   // Listen without proxies, to check that it will work in regular case
   // simulate listening from a web document.
-  ifWindow.addEventListener("message", function listener(event) {
-    ifWindow.removeEventListener("message", listener, false);
+  ifWindow.addEventListener("message", function(event) {
     // As we are in system principal, event is an XrayWrapper
     // xrays use current compartments when calling postMessage method.
     // Whereas js proxies was using postMessage method compartment,
     // not the caller one.
     assert.strictEqual(event.source, helper.xrayWindow,
                       "event.source is the top window");
     assert.equal(event.origin, testHost, "origin matches testHost");
 
     assert.equal(event.data, "{\"foo\":\"bar\\n \\\"escaped\\\".\"}",
                      "message data is correct");
 
     helper.done();
-  }, false);
+  }, {once: true});
 
   helper.createWorker(
     'new ' + function ContentScriptScope() {
       var json = JSON.stringify({foo : "bar\n \"escaped\"."});
 
       document.getElementById("iframe").contentWindow.postMessage(json, "*");
     }
   );
@@ -654,19 +652,17 @@ exports["test Listeners"] = createProxyT
       assert(input, "proxy.getElementById works");
 
       function onclick() {};
       input.onclick = onclick;
       assert(input.onclick === onclick, "on* attributes are equal to original function set");
 
       let addEventListenerCalled = false;
       let expandoCalled = false;
-      input.addEventListener("click", function onclick(event) {
-        input.removeEventListener("click", onclick, true);
-
+      input.addEventListener("click", function (event) {
         assert(!addEventListenerCalled, "closure given to addEventListener is called once");
         if (addEventListenerCalled)
           return;
         addEventListenerCalled = true;
 
         assert(!event.target.ownerDocument.defaultView.documentGlobal, "event object is still wrapped and doesn't expose document globals");
 
         let input2 = document.getElementById("input2");
@@ -685,17 +681,17 @@ exports["test Listeners"] = createProxyT
           }, 0);
 
         }
 
         setTimeout(function () {
           input.click();
         }, 0);
 
-      }, true);
+      }, {capture: true, once: true});
 
       input.click();
     }
   );
 
 });
 
 exports["test requestAnimationFrame"] = createProxyTest("", function (helper) {
@@ -743,31 +739,28 @@ exports["test Cross Domain Iframe"] = cr
   });
 
   let worker = helper.createWorker(
     'new ' + function ContentScriptScope() {
       // Waits for the server page url
       self.on("message", function (url) {
         // Creates an iframe with this page
         let iframe = document.createElement("iframe");
-        iframe.addEventListener("load", function onload() {
-          iframe.removeEventListener("load", onload, true);
+        iframe.addEventListener("load", function() {
           try {
             // Try to communicate with iframe's content
-            window.addEventListener("message", function onmessage(event) {
-              window.removeEventListener("message", onmessage, true);
-
+            window.addEventListener("message", function(event) {
               assert(event.data == "hello world", "COW works properly");
               self.port.emit("end");
-            }, true);
+            }, {capture: true, once: true});
             iframe.contentWindow.postMessage("hello", "*");
           } catch(e) {
             assert(false, "COW fails : "+e.message);
           }
-        }, true);
+        }, {capture: true, once: true});
         iframe.setAttribute("src", url);
         document.body.appendChild(iframe);
       });
     }
   );
 
   worker.port.on("end", function () {
     server.stop(helper.done);
--- a/addon-sdk/source/test/addons/e10s-content/lib/test-content-worker.js
+++ b/addon-sdk/source/test/addons/e10s-content/lib/test-content-worker.js
@@ -45,20 +45,19 @@ function makeWindow() {
 
   return Cc["@mozilla.org/embedcomp/window-watcher;1"].
          getService(Ci.nsIWindowWatcher).
          openWindow(null, url, null, features.join(","), null);
 }
 
 // Listen for only first one occurence of DOM event
 function listenOnce(node, eventName, callback) {
-  node.addEventListener(eventName, function onevent(event) {
-    node.removeEventListener(eventName, onevent, true);
+  node.addEventListener(eventName, function(event) {
     callback(node);
-  }, true);
+  }, {capture: true, once: true});
 }
 
 // Load a given url in a given browser and fires the callback when it is loaded
 function loadAndWait(browser, url, callback) {
   listenOnce(browser, "load", callback);
   // We have to wait before calling `loadURI` otherwise, if we call
   // `loadAndWait` during browser load event, the history will be broken
   setTimeout(function () {
@@ -70,32 +69,31 @@ function loadAndWait(browser, url, callb
 // with a <browser> element loaded on a given content URL
 // The callback receive 3 arguments:
 // - test: reference to the jetpack test object
 // - browser: a reference to the <browser> xul node
 // - done: a callback to call when test is over
 function WorkerTest(url, callback) {
   return function testFunction(assert, done) {
     let chromeWindow = makeWindow();
-    chromeWindow.addEventListener("load", function onload() {
-      chromeWindow.removeEventListener("load", onload, true);
+    chromeWindow.addEventListener("load", function() {
       let browser = chromeWindow.document.createElement("browser");
       browser.setAttribute("type", "content");
       chromeWindow.document.documentElement.appendChild(browser);
       // Wait for about:blank load event ...
       listenOnce(browser, "load", function onAboutBlankLoad() {
         // ... before loading the expected doc and waiting for its load event
         loadAndWait(browser, url, function onDocumentLoaded() {
           callback(assert, browser, function onTestDone() {
 
             close(chromeWindow).then(done);
           });
         });
       });
-    }, true);
+    }, {capture: true, once: true});
   };
 }
 
 exports["test:sample"] = WorkerTest(
   DEFAULT_CONTENT_URL,
   function(assert, browser, done) {
 
     assert.notEqual(browser.contentWindow.location.href, "about:blank",
@@ -762,18 +760,17 @@ exports["test:check worker API with page
 
       // We have to wait before going back into history,
       // otherwise `goBack` won't do anything.
       setTimeout(function () {
         browser.goBack();
       }, 0);
 
       // Wait for the document to be hidden
-      browser.addEventListener("pagehide", function onpagehide() {
-        browser.removeEventListener("pagehide", onpagehide, false);
+      browser.addEventListener("pagehide", function() {
         // Now any event sent to this worker should be cached
 
         worker.postMessage("message");
         worker.port.emit("event");
 
         // Display the page with attached content script back in order to resume
         // its timeout and receive the expected message.
         // We have to delay this in order to not break the history.
@@ -803,17 +800,17 @@ exports["test:check worker API with page
               })
             ]);
             promise.then(done);
           });
 
           browser.goForward();
         }, 500);
 
-      }, false);
+      }, {once: true});
     });
 
   }
 );
 
 exports['test:conentScriptFile as URL instance'] = WorkerTest(
   DEFAULT_CONTENT_URL,
   function(assert, browser, done) {
--- a/addon-sdk/source/test/addons/l10n-properties/app-extension/bootstrap.js
+++ b/addon-sdk/source/test/addons/l10n-properties/app-extension/bootstrap.js
@@ -101,17 +101,17 @@ function startup(data, reasonCode) {
 
     let domain = id.
       toLowerCase().
       replace(/@/g, '-at-').
       replace(/\./g, '-dot-').
       replace(uuidRe, '$1');
 
     let prefixURI = 'resource://' + domain + '/';
-    let resourcesURI = ioService.newURI(rootURI + '/resources/', null, null);
+    let resourcesURI = ioService.newURI(rootURI + '/resources/');
     resourceHandler.setSubstitution(domain, resourcesURI);
 
     // Create path to URLs mapping supported by loader.
     let paths = {
       // Relative modules resolve to add-on package lib
       './': prefixURI + name + '/lib/',
       './tests/': prefixURI + name + '/tests/',
       '': 'resource://gre/modules/commonjs/'
@@ -164,17 +164,17 @@ function startup(data, reasonCode) {
 
       // On mobile, file URI has to end with a `/` otherwise, setSubstitution
       // takes the parent folder instead.
       if (fileURI[fileURI.length-1] !== '/')
         fileURI += '/';
 
       // Maps the given file:// URI to a resource:// in order to avoid various
       // failure that happens with file:// URI and be close to production env
-      let resourcesURI = ioService.newURI(fileURI, null, null);
+      let resourcesURI = ioService.newURI(fileURI);
       let resName = 'extensions.modules.' + domain + '.commonjs.path' + name;
       resourceHandler.setSubstitution(resName, resourcesURI);
 
       result[path] = 'resource://' + resName + '/';
       return result;
     }, paths);
 
     // Make version 2 of the manifest
--- a/addon-sdk/source/test/addons/places/lib/httpd.js
+++ b/addon-sdk/source/test/addons/places/lib/httpd.js
@@ -1641,17 +1641,17 @@ RequestReader.prototype =
       // No absolute paths in the request line in HTTP prior to 1.1
       if (!metadata._httpVersion.atLeast(nsHttpVersion.HTTP_1_1))
         throw HTTP_400;
 
       try
       {
         var uri = Cc["@mozilla.org/network/io-service;1"]
                     .getService(Ci.nsIIOService)
-                    .newURI(fullPath, null, null);
+                    .newURI(fullPath);
         fullPath = uri.path;
         scheme = uri.scheme;
         host = metadata._host = uri.asciiHost;
         port = uri.port;
         if (port === -1)
         {
           if (scheme === "http")
             port = 80;
@@ -4792,17 +4792,17 @@ nsHttpHeaders.prototype =
 */
   setHeader: function(fieldName, fieldValue, merge)
   {
     var name = headerUtils.normalizeFieldName(fieldName);
     var value = headerUtils.normalizeFieldValue(fieldValue);
 
     // The following three headers are stored as arrays because their real-world
     // syntax prevents joining individual headers into a single header using
-    // ",". See also <http://hg.mozilla.org/mozilla-central/diff/9b2a99adc05e/netwerk/protocol/http/src/nsHttpHeaderArray.cpp#l77>
+    // ",". See also <https://hg.mozilla.org/mozilla-central/diff/9b2a99adc05e/netwerk/protocol/http/src/nsHttpHeaderArray.cpp#l77>
     if (merge && name in this._headers)
     {
       if (name === "www-authenticate" ||
           name === "proxy-authenticate" ||
           name === "set-cookie")
       {
         this._headers[name].push(value);
       }
--- a/addon-sdk/source/test/addons/places/lib/places-helper.js
+++ b/addon-sdk/source/test/addons/places/lib/places-helper.js
@@ -1,24 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  'use strict'
 
 const { Cc, Ci, Cu } = require('chrome');
-const bmsrv = Cc['@mozilla.org/browser/nav-bookmarks-service;1'].
-                    getService(Ci.nsINavBookmarksService);
-const hsrv = Cc['@mozilla.org/browser/nav-history-service;1'].
-              getService(Ci.nsINavHistoryService);
-const brsrv = Cc["@mozilla.org/browser/nav-history-service;1"]
-                     .getService(Ci.nsIBrowserHistory);
-const tagsrv = Cc['@mozilla.org/browser/tagging-service;1'].
-              getService(Ci.nsITaggingService);
-const asyncHistory = Cc['@mozilla.org/browser/history;1'].
-              getService(Ci.mozIAsyncHistory);
 const { send } = require('sdk/addon/events');
 const { setTimeout } = require('sdk/timers');
 const { newURI } = require('sdk/url/utils');
 const { defer, all } = require('sdk/core/promise');
 const { once } = require('sdk/system/events');
 const { set } = require('sdk/preferences/service');
 const {
   Bookmark, Group, Separator,
@@ -36,17 +26,17 @@ function invalidResolve (assert) {
     assert.fail('Resolve state should not be called: ' + e);
   };
 }
 exports.invalidResolve = invalidResolve;
 
 // Removes all children of group
 function clearBookmarks (group) {
   group
-   ? bmsrv.removeFolderChildren(group.id)
+   ? PlacesUtils.bookmarks.removeFolderChildren(group.id)
    : clearAllBookmarks();
 }
 
 function clearAllBookmarks () {
   [MENU, TOOLBAR, UNSORTED].forEach(clearBookmarks);
 }
 
 function clearHistory (done) {
@@ -60,72 +50,75 @@ function resetPlaces (done) {
   set('places.database.lastMaintenance', Math.floor(Date.now() / 1000));
   clearAllBookmarks();
   clearHistory(done);
 }
 exports.resetPlaces = resetPlaces;
 
 function compareWithHost (assert, item) {
   let id = item.id;
-  let type = item.type === 'group' ? bmsrv.TYPE_FOLDER : bmsrv['TYPE_' + item.type.toUpperCase()];
+  let type = item.type === 'group' ?
+    PlacesUtils.bookmarks.TYPE_FOLDER :
+    PlacesUtils.bookmarks['TYPE_' + item.type.toUpperCase()];
   let url = item.url && !item.url.endsWith('/') ? item.url + '/' : item.url;
 
-  if (type === bmsrv.TYPE_BOOKMARK) {
-    assert.equal(url, bmsrv.getBookmarkURI(id).spec.toString(), 'Matches host url');
-    let tags = tagsrv.getTagsForURI(newURI(item.url));
+  if (type === PlacesUtils.bookmarks.TYPE_BOOKMARK) {
+    assert.equal(url, PlacesUtils.bookmarks.getBookmarkURI(id).spec.toString(),
+                 'Matches host url');
+    let tags = PlacesUtils.tagging.getTagsForURI(newURI(item.url));
     for (let tag of tags) {
       // Handle both array for raw data and set for instances
       if (Array.isArray(item.tags))
         assert.ok(~item.tags.indexOf(tag), 'has correct tag');
       else
         assert.ok(item.tags.has(tag), 'has correct tag');
     }
     assert.equal(tags.length,
       Array.isArray(item.tags) ? item.tags.length : item.tags.size,
       'matches tag count');
   }
-  if (type !== bmsrv.TYPE_SEPARATOR) {
-    assert.equal(item.title, bmsrv.getItemTitle(id), 'Matches host title');
+  if (type !== PlacesUtils.bookmarks.TYPE_SEPARATOR) {
+    assert.equal(item.title, PlacesUtils.bookmarks.getItemTitle(id),
+                 'Matches host title');
   }
-  assert.equal(item.index, bmsrv.getItemIndex(id), 'Matches host index');
-  assert.equal(item.group.id || item.group, bmsrv.getFolderIdForItem(id), 'Matches host group id');
-  assert.equal(type, bmsrv.getItemType(id), 'Matches host type');
+  assert.equal(item.index, PlacesUtils.bookmarks.getItemIndex(id),
+               'Matches host index');
+  assert.equal(item.group.id || item.group,
+               PlacesUtils.bookmarks.getFolderIdForItem(id),
+               'Matches host group id');
+  assert.equal(type, PlacesUtils.bookmarks.getItemType(id),
+               'Matches host type');
 }
 exports.compareWithHost = compareWithHost;
 
+/**
+ * Adds visits to places.
+ *
+ * @param {Array|String} urls Either an array of urls to add, or a single url
+ *                            as a string.
+ */
 function addVisits (urls) {
-  var deferred = defer();
-  asyncHistory.updatePlaces([].concat(urls).map(createVisit), {
-    handleResult: function () {},
-    handleError: deferred.reject,
-    handleCompletion: deferred.resolve
-  });
-
-  return deferred.promise;
+  return PlacesUtils.history.insertMany([].concat(urls).map(createVisit));
 }
 exports.addVisits = addVisits;
 
 function removeVisits (urls) {
-  [].concat(urls).map(url => {
-    hsrv.removePage(newURI(url));
-  });
+  PlacesUtils.history.remove(urls);
 }
 exports.removeVisits = removeVisits;
 
 // Creates a mozIVisitInfo object
 function createVisit (url) {
-  let place = {}
-  place.uri = newURI(url);
-  place.title = "Test visit for " + place.uri.spec;
-  place.visits = [{
-    transitionType: hsrv.TRANSITION_LINK,
-    visitDate: +(new Date()) * 1000,
-    referredURI: undefined
-  }];
-  return place;
+  return {
+    url,
+    title: "Test visit for " + url,
+    visits: [{
+      transition: PlacesUtils.history.TRANSITION_LINK
+    }]
+  };
 }
 
 function createBookmark (data) {
   data = data || {};
   let item = {
     title: data.title || 'Moz',
     url: data.url || (!data.type || data.type === 'bookmark' ?
       'http://moz.com/' :
@@ -136,17 +129,17 @@ function createBookmark (data) {
     type: data.type || 'bookmark',
     group: data.group
   };
   return send('sdk-places-bookmarks-create', item);
 }
 exports.createBookmark = createBookmark;
 
 function historyBatch () {
-  hsrv.runInBatchMode(() => {}, null);
+  PlacesUtils.history.runInBatchMode(() => {}, null);
 }
 exports.historyBatch = historyBatch;
 
 function createBookmarkItem (data) {
   let deferred = defer();
   data = data || {};
   save({
     title: data.title || 'Moz',
--- a/addon-sdk/source/test/addons/places/lib/test-places-history.js
+++ b/addon-sdk/source/test/addons/places/lib/test-places-history.js
@@ -31,19 +31,19 @@ exports.testEmptyQuery = function*(asser
   ]);
 
   let results = yield searchP();
   assert.equal(results.length, 2, 'Correct number of entries returned');
   assert.equal(results[0].url, 'http://simplequery-1.com/',
     'matches url');
   assert.equal(results[1].url, 'http://simplequery-2.com/',
     'matches url');
-  assert.equal(results[0].title, 'Test visit for ' + results[0].url,
+  assert.equal(results[0].title, 'Test visit for ' + 'http://simplequery-1.com',
     'title matches');
-  assert.equal(results[1].title, 'Test visit for ' + results[1].url,
+  assert.equal(results[1].title, 'Test visit for ' + 'http://simplequery-2.com',
     'title matches');
   assert.equal(results[0].visitCount, 1, 'matches access');
   assert.equal(results[1].visitCount, 1, 'matches access');
   assert.ok(within(results[0].time), 'accurate access time');
   assert.ok(within(results[1].time), 'accurate access time');
   assert.equal(Object.keys(results[0]).length, 4,
     'no addition exposed properties on history result');
 };
--- a/addon-sdk/source/test/addons/private-browsing-supported/sidebar/utils.js
+++ b/addon-sdk/source/test/addons/private-browsing-supported/sidebar/utils.js
@@ -35,27 +35,27 @@ function getExtraSidebarMenuitems() {
 exports.getExtraSidebarMenuitems = getExtraSidebarMenuitems;
 
 function makeID(id) {
   return 'jetpack-sidebar-' + id;
 }
 exports.makeID = makeID;
 
 function simulateCommand(ele) {
-  let window = ele.ownerDocument.defaultView;
+  let window = ele.ownerGlobal;
   let { document } = window;
   var evt = document.createEvent('XULCommandEvent');
   evt.initCommandEvent('command', true, true, window,
     0, false, false, false, false, null);
   ele.dispatchEvent(evt);
 }
 exports.simulateCommand = simulateCommand;
 
 function simulateClick(ele) {
-  let window = ele.ownerDocument.defaultView;
+  let window = ele.ownerGlobal;
   let { document } = window;
   let evt = document.createEvent('MouseEvents');
   evt.initMouseEvent('click', true, true, window,
     0, 0, 0, 0, 0, false, false, false, false, 0, null);
   ele.dispatchEvent(evt);
 }
 exports.simulateClick = simulateClick;
 
--- a/addon-sdk/source/test/addons/simple-prefs-regression/app-extension/bootstrap.js
+++ b/addon-sdk/source/test/addons/simple-prefs-regression/app-extension/bootstrap.js
@@ -101,17 +101,17 @@ function startup(data, reasonCode) {
 
     let domain = id.
       toLowerCase().
       replace(/@/g, '-at-').
       replace(/\./g, '-dot-').
       replace(uuidRe, '$1');
 
     let prefixURI = 'resource://' + domain + '/';
-    let resourcesURI = ioService.newURI(rootURI + '/resources/', null, null);
+    let resourcesURI = ioService.newURI(rootURI + '/resources/');
     resourceHandler.setSubstitution(domain, resourcesURI);
 
     // Create path to URLs mapping supported by loader.
     let paths = {
       // Relative modules resolve to add-on package lib
       './': prefixURI + name + '/lib/',
       './tests/': prefixURI + name + '/tests/',
       '': 'resource://gre/modules/commonjs/'
@@ -164,17 +164,17 @@ function startup(data, reasonCode) {
 
       // On mobile, file URI has to end with a `/` otherwise, setSubstitution
       // takes the parent folder instead.
       if (fileURI[fileURI.length-1] !== '/')
         fileURI += '/';
 
       // Maps the given file:// URI to a resource:// in order to avoid various
       // failure that happens with file:// URI and be close to production env
-      let resourcesURI = ioService.newURI(fileURI, null, null);
+      let resourcesURI = ioService.newURI(fileURI);
       let resName = 'extensions.modules.' + domain + '.commonjs.path' + name;
       resourceHandler.setSubstitution(resName, resourcesURI);
 
       result[path] = 'resource://' + resName + '/';
       return result;
     }, paths);
 
     // Make version 2 of the manifest
--- a/addon-sdk/source/test/addons/unsafe-content-script/main.js
+++ b/addon-sdk/source/test/addons/unsafe-content-script/main.js
@@ -24,17 +24,17 @@ exports.testMembranelessMode = function(
     nodeName: "iframe",
     type: "content",
     allowJavascript: true,
     allowPlugins: true,
     allowAuth: true,
     uri: url
   });
 
-  element.addEventListener("DOMContentLoaded", onDOMReady, false);
+  element.addEventListener("DOMContentLoaded", onDOMReady);
 
   function onDOMReady() {
     let worker = Worker({
       window: element.contentWindow,
       contentScript:
         'new ' + function () {
           var assert = function assert(v, msg) {
             self.port.emit("assert", { assertion: v, msg: msg });
@@ -46,17 +46,17 @@ exports.testMembranelessMode = function(
           window.wrappedJSObject.assert = assert;
           window.wrappedJSObject.runTest();
           done();
         }
     });
 
     worker.port.on("done", () => {
       // cleanup
-      element.parentNode.removeChild(element);
+      element.remove();
       worker.destroy();
       loader.unload();
 
       done();
     });
 
     worker.port.on("assert", function (data) {
       assert.ok(data.assertion, data.msg);
--- a/addon-sdk/source/test/context-menu/util.js
+++ b/addon-sdk/source/test/context-menu/util.js
@@ -37,23 +37,23 @@ exports.openTab = openTab;
 
 const openContextMenu = (selector, tab=getActiveTab()) => {
   const browser = tabUtils.getBrowserForTab(tab);
   browser.
     messageManager.
     sendAsyncMessage("sdk/test/context-menu/open",
                      {target: selector});
 
-  return when(tab.ownerDocument.defaultView, "popupshown").
+  return when(tab.ownerGlobal, "popupshown").
           then(_target);
 };
 exports.openContextMenu = openContextMenu;
 
 const closeContextMenu = (menu) => {
-  const result = when(menu.ownerDocument.defaultView, "popuphidden").
+  const result = when(menu.ownerGlobal, "popuphidden").
                   then(_target);
 
   menu.hidePopup();
   return result;
 };
 exports.closeContextMenu = closeContextMenu;
 
 const closeTab = (tab) => {
--- a/addon-sdk/source/test/event/helpers.js
+++ b/addon-sdk/source/test/event/helpers.js
@@ -34,20 +34,19 @@ const wait = function(target, type, capt
   }
   else if (typeof(target) === "number") {
     setTimeout(resolve, target);
   }
   else if (typeof(target.once) === "function") {
     target.once(type, resolve);
   }
   else if (typeof(target.addEventListener) === "function") {
-    target.addEventListener(type, function listener(...args) {
-      this.removeEventListener(type, listener, capture);
+    target.addEventListener(type, function(...args) {
       resolve(...args);
-    }, capture);
+    }, {capture, once: true});
   }
   else if (typeof(target) === "object" && target !== null) {
     once(target, type, resolve);
   }
   else {
     reject('Invalid target given.');
   }
 
--- a/addon-sdk/source/test/fixtures/test-addon-extras.html
+++ b/addon-sdk/source/test/fixtures/test-addon-extras.html
@@ -20,12 +20,12 @@
 
     window.addEventListener("message", function getMessage({ data }) {
       if (data.name == "start") {
         window.postMessage({
           name: "extras",
           result: window.extras === undefined
         }, '*');
       }
-    }, false);
+    });
   </script>
 </body>
 </html>
--- a/addon-sdk/source/test/jetpack-package.ini
+++ b/addon-sdk/source/test/jetpack-package.ini
@@ -45,16 +45,17 @@ generated-files =
 subsuite = clipboard
 [test-collection.js]
 [test-commonjs-test-adapter.js]
 [test-content-events.js]
 [test-content-script.js]
 [test-content-sync-worker.js]
 [test-content-worker.js]
 [test-context-menu.js]
+skip-if = asan # Bug 1333359
 [test-context-menu@2.js]
 [test-cuddlefish.js]
 # Cuddlefish loader is unsupported
 skip-if = true
 [test-deprecate.js]
 [test-dev-panel.js]
 [test-diffpatcher.js]
 [test-dispatcher.js]
@@ -101,16 +102,17 @@ skip-if = true
 [test-node-os.js]
 [test-notifications.js]
 [test-object.js]
 [test-observers.js]
 [test-page-mod-debug.js]
 [test-page-mod.js]
 [test-page-worker.js]
 [test-panel.js]
+skip-if = asan # Bug 1333359
 [test-passwords-utils.js]
 [test-passwords.js]
 [test-path.js]
 [test-plain-text-console.js]
 [test-preferences-service.js]
 [test-preferences-target.js]
 [test-private-browsing.js]
 [test-promise.js]
@@ -168,12 +170,13 @@ skip-if = true
 [test-uuid.js]
 [test-weak-set.js]
 [test-window-events.js]
 [test-window-observer.js]
 [test-window-utils-private-browsing.js]
 [test-window-utils.js]
 [test-window-utils2.js]
 [test-windows-common.js]
+skip-if = asan # bug 1333357
 [test-windows.js]
 [test-xhr.js]
 [test-xpcom.js]
 [test-xul-app.js]
--- a/addon-sdk/source/test/leak/leak-utils.js
+++ b/addon-sdk/source/test/leak/leak-utils.js
@@ -55,17 +55,17 @@ exports.asyncWindowLeakTest = function*(
   }
   Services.obs.addObserver(windowObserver, "domwindowopened", false);
 
   // Execute the body of the test.
   let testLoader = yield asyncTestFunc(assert);
 
   // Stop tracking new windows and attempt to GC any resources allocated
   // by the test body.
-  Services.obs.removeObserver(windowObserver, "domwindowopened", false);
+  Services.obs.removeObserver(windowObserver, "domwindowopened");
   yield gc();
 
   // Check to see if any of the windows we saw survived the GC.  We consider
   // these leaks.
   assert.ok(weakWindows.length > 0, "should see at least one new window");
   for (let i = 0; i < weakWindows.length; ++i) {
     assert.equal(weakWindows[i].get(), null, "window " + i + " should be GC'd");
   }
--- a/addon-sdk/source/test/leak/test-leak-event-dom-closed-window.js
+++ b/addon-sdk/source/test/leak/test-leak-event-dom-closed-window.js
@@ -8,22 +8,21 @@ const { Loader } = require('sdk/test/loa
 const openWindow = require("sdk/window/utils").open;
 
 exports["test sdk/event/dom does not leak when attached to closed window"] = function*(assert) {
   yield asyncWindowLeakTest(assert, _ => {
     return new Promise(resolve => {
       let loader = Loader(module);
       let { open } = loader.require('sdk/event/dom');
       let w = openWindow();
-      w.addEventListener("DOMWindowClose", function windowClosed(evt) {
-        w.removeEventListener("DOMWindowClose", windowClosed);
+      w.addEventListener("DOMWindowClose", function(evt) {
         // The sdk/event/dom module tries to clean itself up when DOMWindowClose
         // is fired.  Verify that it doesn't leak if its attached to an
         // already closed window either. (See bug 1268898.)
         open(w.document, "TestEvent1");
         resolve(loader);
-      });
+      }, {once: true});
       w.close();
     });
   });
 }
 
 require("sdk/test").run(exports);
--- a/addon-sdk/source/test/leak/test-leak-tab-events.js
+++ b/addon-sdk/source/test/leak/test-leak-tab-events.js
@@ -8,39 +8,35 @@ const { Loader } = require('sdk/test/loa
 const openWindow = require("sdk/window/utils").open;
 
 exports["test sdk/tab/events does not leak new window"] = function*(assert) {
   yield asyncWindowLeakTest(assert, _ => {
     return new Promise(resolve => {
       let loader = Loader(module);
       let { events } = loader.require('sdk/tab/events');
       let w = openWindow();
-      w.addEventListener("load", function windowLoaded(evt) {
-        w.removeEventListener("load", windowLoaded);
-        w.addEventListener("DOMWindowClose", function windowClosed(evt) {
-          w.removeEventListener("DOMWindowClose", windowClosed);
+      w.addEventListener("load", function(evt) {
+        w.addEventListener("DOMWindowClose", function(evt) {
           resolve(loader);
-        });
+        }, {once: true});
         w.close();
-      });
+      }, {once: true});
     });
   });
 }
 
 exports["test sdk/tab/events does not leak when attached to existing window"] = function*(assert) {
   yield asyncWindowLeakTest(assert, _ => {
     return new Promise(resolve => {
       let loader = Loader(module);
       let w = openWindow();
-      w.addEventListener("load", function windowLoaded(evt) {
-        w.removeEventListener("load", windowLoaded);
+      w.addEventListener("load", function(evt) {
         let { events } = loader.require('sdk/tab/events');
-        w.addEventListener("DOMWindowClose", function windowClosed(evt) {
-          w.removeEventListener("DOMWindowClose", windowClosed);
+        w.addEventListener("DOMWindowClose", function(evt) {
           resolve(loader);
-        });
+        }, {once: true});
         w.close();
-      });
+      }, {once: true});
     });
   });
 }
 
 require("sdk/test").run(exports);
--- a/addon-sdk/source/test/leak/test-leak-window-events.js
+++ b/addon-sdk/source/test/leak/test-leak-window-events.js
@@ -44,22 +44,20 @@ exports["test window/events for leaks"] 
   });
 };
 
 exports["test window/events for leaks with existing window"] = function*(assert) {
   yield asyncWindowLeakTest(assert, _ => {
     return new Promise((resolve, reject) => {
       let loader = Loader(module);
       let w = open();
-      w.addEventListener("load", function windowLoaded(evt) {
-        w.removeEventListener("load", windowLoaded);
+      w.addEventListener("load", function(evt) {
         let { events } = loader.require("sdk/window/events");
-        w.addEventListener("DOMWindowClose", function windowClosed(evt) {
-          w.removeEventListener("DOMWindowClose", windowClosed);
+        w.addEventListener("DOMWindowClose", function(evt) {
           resolve(loader);
-        });
+        }, {once: true});
         w.close();
-      });
+      }, {once: true});
     });
   });
 };
 
 require("sdk/test").run(exports);
--- a/addon-sdk/source/test/lib/httpd.js
+++ b/addon-sdk/source/test/lib/httpd.js
@@ -1642,17 +1642,17 @@ RequestReader.prototype =
       // No absolute paths in the request line in HTTP prior to 1.1
       if (!metadata._httpVersion.atLeast(nsHttpVersion.HTTP_1_1))
         throw HTTP_400;
 
       try
       {
         var uri = Cc["@mozilla.org/network/io-service;1"]
                     .getService(Ci.nsIIOService)
-                    .newURI(fullPath, null, null);
+                    .newURI(fullPath);
         fullPath = uri.path;
         scheme = uri.scheme;
         host = metadata._host = uri.asciiHost;
         port = uri.port;
         if (port === -1)
         {
           if (scheme === "http")
             port = 80;
@@ -4793,17 +4793,17 @@ nsHttpHeaders.prototype =
 */
   setHeader: function(fieldName, fieldValue, merge)
   {
     var name = headerUtils.normalizeFieldName(fieldName);
     var value = headerUtils.normalizeFieldValue(fieldValue);
 
     // The following three headers are stored as arrays because their real-world
     // syntax prevents joining individual headers into a single header using
-    // ",". See also <http://hg.mozilla.org/mozilla-central/diff/9b2a99adc05e/netwerk/protocol/http/src/nsHttpHeaderArray.cpp#l77>
+    // ",". See also <https://hg.mozilla.org/mozilla-central/diff/9b2a99adc05e/netwerk/protocol/http/src/nsHttpHeaderArray.cpp#l77>
     if (merge && name in this._headers)
     {
       if (name === "www-authenticate" ||
           name === "proxy-authenticate" ||
           name === "set-cookie")
       {
         this._headers[name].push(value);
       }
--- a/addon-sdk/source/test/preferences/firefox.json
+++ b/addon-sdk/source/test/preferences/firefox.json
@@ -1,11 +1,13 @@
 {
   "browser.startup.homepage": "about:blank",
   "startup.homepage_welcome_url": "about:blank",
   "devtools.browsertoolbox.panel": "jsdebugger",
   "devtools.chrome.enabled": true,
   "urlclassifier.updateinterval": 172800,
   "browser.safebrowsing.provider.google.gethashURL": "http://localhost/safebrowsing-dummy/gethash",
   "browser.safebrowsing.provider.google.updateURL": "http://localhost/safebrowsing-dummy/update",
+  "browser.safebrowsing.provider.google4.gethashURL": "http://localhost/safebrowsing4-dummy/gethash",
+  "browser.safebrowsing.provider.google4.updateURL": "http://localhost/safebrowsing4-dummy/update",
   "browser.safebrowsing.provider.mozilla.gethashURL": "http://localhost/safebrowsing-dummy/gethash",
   "browser.safebrowsing.provider.mozilla.updateURL": "http://localhost/safebrowsing-dummy/update"
 }
--- a/addon-sdk/source/test/preferences/no-connections.json
+++ b/addon-sdk/source/test/preferences/no-connections.json
@@ -14,16 +14,19 @@
   "browser.aboutHomeSnippets.updateUrl": "https://localhost/snippet-dummy",
   "browser.newtab.url": "about:blank",
   "browser.search.update": false,
   "browser.search.suggest.enabled": false,
   "browser.safebrowsing.phishing.enabled": false,
   "browser.safebrowsing.provider.google.updateURL": "http://localhost/safebrowsing-dummy/update",
   "browser.safebrowsing.provider.google.gethashURL": "http://localhost/safebrowsing-dummy/gethash",
   "browser.safebrowsing.provider.google.reportURL": "http://localhost/safebrowsing-dummy/malwarereport",
+  "browser.safebrowsing.provider.google4.updateURL": "http://localhost/safebrowsing4-dummy/update",
+  "browser.safebrowsing.provider.google4.gethashURL": "http://localhost/safebrowsing4-dummy/gethash",
+  "browser.safebrowsing.provider.google4.reportURL": "http://localhost/safebrowsing4-dummy/malwarereport",
   "browser.selfsupport.url": "https://localhost/selfsupport-dummy",
   "browser.safebrowsing.provider.mozilla.gethashURL": "http://localhost/safebrowsing-dummy/gethash",
   "browser.safebrowsing.provider.mozilla.updateURL": "http://localhost/safebrowsing-dummy/update",
   "browser.newtabpage.directory.source": "data:application/json,{'jetpack':1}",
   "browser.newtabpage.directory.ping": "",
   "extensions.update.url": "http://localhost/extensions-dummy/updateURL",
   "extensions.update.background.url": "http://localhost/extensions-dummy/updateBackgroundURL",
   "extensions.blocklist.url": "http://localhost/extensions-dummy/blocklistURL",
--- a/addon-sdk/source/test/preferences/test.json
+++ b/addon-sdk/source/test/preferences/test.json
@@ -26,21 +26,19 @@
   "security.default_personal_cert": "Select Automatically",
   "network.http.prompt-temp-redirect": false,
   "security.warn_viewing_mixed": false,
   "extensions.defaultProviders.enabled": true,
   "datareporting.policy.dataSubmissionPolicyBypassNotification": true,
   "layout.css.report_errors": true,
   "layout.css.grid.enabled": true,
   "layout.spammy_warnings.enabled": false,
-  "dom.mozSettings.enabled": true,
   "network.http.bypass-cachelock-threshold": 200000,
   "geo.provider.testing": true,
   "browser.pagethumbnails.capturing_disabled": true,
   "browser.download.panel.shown": true,
   "general.useragent.updates.enabled": false,
   "media.eme.enabled": true,
-  "media.eme.apiVisible": true,
   "dom.ipc.tabs.shutdownTimeoutSecs": 0,
   "general.useragent.locale": "en-US",
   "intl.locale.matchOS": "en-US",
   "dom.indexedDB.experimental": true
 }
--- a/addon-sdk/source/test/sidebar/utils.js
+++ b/addon-sdk/source/test/sidebar/utils.js
@@ -42,27 +42,27 @@ function getExtraSidebarMenuitems() {
 exports.getExtraSidebarMenuitems = getExtraSidebarMenuitems;
 
 function makeID(id) {
   return 'jetpack-sidebar-' + id;
 }
 exports.makeID = makeID;
 
 function simulateCommand(ele) {
-  let window = ele.ownerDocument.defaultView;
+  let window = ele.ownerGlobal;
   let { document } = window;
   var evt = document.createEvent('XULCommandEvent');
   evt.initCommandEvent('command', true, true, window,
     0, false, false, false, false, null);
   ele.dispatchEvent(evt);
 }
 exports.simulateCommand = simulateCommand;
 
 function simulateClick(ele) {
-  let window = ele.ownerDocument.defaultView;
+  let window = ele.ownerGlobal;
   let { document } = window;
   let evt = document.createEvent('MouseEvents');
   evt.initMouseEvent('click', true, true, window,
     0, 0, 0, 0, 0, false, false, false, false, 0, null);
   ele.dispatchEvent(evt);
 }
 exports.simulateClick = simulateClick;
 
--- a/addon-sdk/source/test/tabs/utils.js
+++ b/addon-sdk/source/test/tabs/utils.js
@@ -8,17 +8,16 @@ const { openTab: makeTab, getTabContentW
 function openTab(rawWindow, url) {
   return new Promise(resolve => {
     let tab = makeTab(rawWindow, url);
     let window = getTabContentWindow(tab);
     if (window.document.readyState == "complete") {
       return resolve();
     }
 
-    window.addEventListener("load", function onLoad() {
-      window.removeEventListener("load", onLoad, true);
+    window.addEventListener("load", function() {
       resolve();
-    }, true);
+    }, {capture: true, once: true});
 
     return null;
   })
 }
 exports.openTab = openTab;
--- a/addon-sdk/source/test/test-clipboard.js
+++ b/addon-sdk/source/test/test-clipboard.js
@@ -2,85 +2,32 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 require("sdk/clipboard");
 
 const { Cc, Ci } = require("chrome");
 
-const imageTools = Cc["@mozilla.org/image/tools;1"].
-                    getService(Ci.imgITools);
+const imageTools = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools);
+const io = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].getService(Ci.nsIAppShellService);
 
-const io = Cc["@mozilla.org/network/io-service;1"].
-                    getService(Ci.nsIIOService);
-
+const XHTML_NS = "http://www.w3.org/1999/xhtml";
 const base64png = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYA" +
                   "AABzenr0AAAASUlEQVRYhe3O0QkAIAwD0eyqe3Q993AQ3cBSUKpygfsNTy" +
                   "N5ugbQpK0BAADgP0BRDWXWlwEAAAAAgPsA3rzDaAAAAHgPcGrpgAnzQ2FG" +
                   "bWRR9AAAAABJRU5ErkJggg%3D%3D";
 
 const { base64jpeg } = require("./fixtures");
 
 const { platform } = require("sdk/system");
 // For Windows, Mac and Linux, platform returns the following: winnt, darwin and linux.
 var isWindows = platform.toLowerCase().indexOf("win") == 0;
 
-const canvasHTML = "data:text/html," + encodeURIComponent(
-  "<html>\
-    <body>\
-      <canvas width='32' height='32'></canvas>\
-    </body>\
-  </html>"
-);
-
-function comparePixelImages(imageA, imageB, callback) {
-  let tabs = require("sdk/tabs");
-
-  tabs.open({
-    url: canvasHTML,
-
-    onReady: function onReady(tab) {
-      let worker = tab.attach({
-        contentScript: "new " + function() {
-          let canvas = document.querySelector("canvas");
-          let context = canvas.getContext("2d");
-
-          self.port.on("draw-image", function(imageURI) {
-            let img = new Image();
-
-            img.onload = function() {
-              context.drawImage(this, 0, 0);
-
-              let pixels = Array.join(context.getImageData(0, 0, 32, 32).data);
-              self.port.emit("image-pixels", pixels);
-            }
-
-            img.src = imageURI;
-          });
-        }
-      });
-
-      let compared = "";
-
-      worker.port.on("image-pixels", function (pixels) {
-        if (!compared) {
-          compared = pixels;
-          this.emit("draw-image", imageB);
-        } else {
-          tab.close(callback.bind(null, compared === pixels))
-        }
-      });
-
-      worker.port.emit("draw-image", imageA);
-    }
-  });
-}
-
-
 // Test the typical use case, setting & getting with no flavors specified
 exports["test With No Flavor"] = function(assert) {
   var contents = "hello there";
   var flavor = "text";
   var fullFlavor = "text/unicode";
   var clip = require("sdk/clipboard");
 
   // Confirm we set the clipboard
@@ -155,30 +102,49 @@ exports["test Set Image"] = function(ass
   var clip = require("sdk/clipboard");
   var flavor = "image";
   var fullFlavor = "image/png";
 
   assert.ok(clip.set(base64png, flavor), "clipboard set");
   assert.equal(clip.currentFlavors[0], flavor, "flavor is set");
 };
 
-exports["test Get Image"] = function(assert, done) {
+exports["test Get Image"] = function* (assert) {
   var clip = require("sdk/clipboard");
 
   clip.set(base64png, "image");
 
   var contents = clip.get();
+  const hiddenWindow = appShellService.hiddenDOMWindow;
+  const Image = hiddenWindow.Image;
+  const canvas = hiddenWindow.document.createElementNS(XHTML_NS, "canvas");
+  let context = canvas.getContext("2d");
 
-  comparePixelImages(base64png, contents, function (areEquals) {
-    assert.ok(areEquals,
-      "Image gets from clipboard equals to image sets to the clipboard");
+  const imageURLToPixels = (imageURL) => {
+    return new Promise((resolve) => {
+      let img = new Image();
+
+      img.onload = function() {
+        context.drawImage(this, 0, 0);
+
+        let pixels = Array.join(context.getImageData(0, 0, 32, 32).data);
+        resolve(pixels);
+      };
 
-    done();
-  });
-}
+      img.src = imageURL;
+    });
+  };
+
+  let [base64pngPixels, clipboardPixels] = yield Promise.all([
+    imageURLToPixels(base64png), imageURLToPixels(contents),
+  ]);
+
+  assert.ok(base64pngPixels === clipboardPixels,
+            "Image gets from clipboard equals to image sets to the clipboard");
+};
 
 exports["test Set Image Type Not Supported"] = function(assert) {
   var clip = require("sdk/clipboard");
   var flavor = "image";
 
   assert.throws(function () {
     clip.set(base64jpeg, flavor);
   }, "Invalid flavor for image/jpeg");
--- a/addon-sdk/source/test/test-content-script.js
+++ b/addon-sdk/source/test/test-content-script.js
@@ -23,44 +23,43 @@ function createProxyTest(html, callback)
       nodeName: "iframe",
       type: "content",
       allowJavascript: true,
       allowPlugins: true,
       allowAuth: true,
       uri: testURI
     });
 
-    element.addEventListener("DOMContentLoaded", onDOMReady, false);
+    element.addEventListener("DOMContentLoaded", onDOMReady);
 
     function onDOMReady() {
       // Reload frame after getting principal from `testURI`
       if (!principalLoaded) {
         element.setAttribute("src", url);
         principalLoaded = true;
         return;
       }
 
       assert.equal(element.getAttribute("src"), url, "correct URL loaded");
-      element.removeEventListener("DOMContentLoaded", onDOMReady,
-                                                  false);
+      element.removeEventListener("DOMContentLoaded", onDOMReady);
       let xrayWindow = element.contentWindow;
       let rawWindow = xrayWindow.wrappedJSObject;
 
       let isDone = false;
       let helper = {
         xrayWindow: xrayWindow,
         rawWindow: rawWindow,
         createWorker: function (contentScript) {
           return createWorker(assert, xrayWindow, contentScript, helper.done);
         },
         done: function () {
           if (isDone)
             return;
           isDone = true;
-          element.parentNode.removeChild(element);
+          element.remove();
           done();
         }
       };
       callback(helper, assert);
     }
   };
 }
 
@@ -169,31 +168,30 @@ exports["test Shared To String Proxies"]
 */
 
 // Ensure that postMessage is working correctly across documents with an iframe
 var html = '<iframe id="iframe" name="test" src="data:text/html;charset=utf-8," />';
 exports["test postMessage"] = createProxyTest(html, function (helper, assert) {
   let ifWindow = helper.xrayWindow.document.getElementById("iframe").contentWindow;
   // Listen without proxies, to check that it will work in regular case
   // simulate listening from a web document.
-  ifWindow.addEventListener("message", function listener(event) {
-    ifWindow.removeEventListener("message", listener, false);
+  ifWindow.addEventListener("message", function(event) {
     // As we are in system principal, event is an XrayWrapper
     // xrays use current compartments when calling postMessage method.
     // Whereas js proxies was using postMessage method compartment,
     // not the caller one.
     assert.strictEqual(event.source, helper.xrayWindow,
                       "event.source is the top window");
     assert.equal(event.origin, testHost, "origin matches testHost");
 
     assert.equal(event.data, "{\"foo\":\"bar\\n \\\"escaped\\\".\"}",
                      "message data is correct");
 
     helper.done();
-  }, false);
+  }, {once: true});
 
   helper.createWorker(
     'new ' + function ContentScriptScope() {
       var json = JSON.stringify({foo : "bar\n \"escaped\"."});
 
       document.getElementById("iframe").contentWindow.postMessage(json, "*");
     }
   );
@@ -655,18 +653,16 @@ exports["test Listeners"] = createProxyT
 
       function onclick() {};
       input.onclick = onclick;
       assert(input.onclick === onclick, "on* attributes are equal to original function set");
 
       let addEventListenerCalled = false;
       let expandoCalled = false;
       input.addEventListener("click", function onclick(event) {
-        input.removeEventListener("click", onclick, true);
-
         assert(!addEventListenerCalled, "closure given to addEventListener is called once");
         if (addEventListenerCalled)
           return;
         addEventListenerCalled = true;
 
         assert(!event.target.ownerDocument.defaultView.documentGlobal, "event object is still wrapped and doesn't expose document globals");
 
         let input2 = document.getElementById("input2");
@@ -685,17 +681,17 @@ exports["test Listeners"] = createProxyT
           }, 0);
 
         }
 
         setTimeout(function () {
           input.click();
         }, 0);
 
-      }, true);
+      }, {capture: true, once: true});
 
       input.click();
     }
   );
 
 });
 
 exports["test requestAnimationFrame"] = createProxyTest("", function (helper) {
@@ -743,31 +739,28 @@ exports["test Cross Domain Iframe"] = cr
   });
 
   let worker = helper.createWorker(
     'new ' + function ContentScriptScope() {
       // Waits for the server page url
       self.on("message", function (url) {
         // Creates an iframe with this page
         let iframe = document.createElement("iframe");
-        iframe.addEventListener("load", function onload() {
-          iframe.removeEventListener("load", onload, true);
+        iframe.addEventListener("load", function() {
           try {
             // Try to communicate with iframe's content
-            window.addEventListener("message", function onmessage(event) {
-              window.removeEventListener("message", onmessage, true);
-
+            window.addEventListener("message", function(event) {
               assert(event.data == "hello world", "COW works properly");
               self.port.emit("end");
-            }, true);
+            }, {capture: true, once: true});
             iframe.contentWindow.postMessage("hello", "*");
           } catch(e) {
             assert(false, "COW fails : "+e.message);
           }
-        }, true);
+        }, {capture: true, once: true});
         iframe.setAttribute("src", url);
         document.body.appendChild(iframe);
       });
     }
   );
 
   worker.port.on("end", function () {
     server.stop(helper.done);
--- a/addon-sdk/source/test/test-content-sync-worker.js
+++ b/addon-sdk/source/test/test-content-sync-worker.js
@@ -44,20 +44,19 @@ function makeWindow() {
 
   return Cc["@mozilla.org/embedcomp/window-watcher;1"].
          getService(Ci.nsIWindowWatcher).
          openWindow(null, url, null, features.join(","), null);
 }
 
 // Listen for only first one occurence of DOM event
 function listenOnce(node, eventName, callback) {
-  node.addEventListener(eventName, function onevent(event) {
-    node.removeEventListener(eventName, onevent, true);
+  node.addEventListener(eventName, function(event) {
     callback(node);
-  }, true);
+  }, {capture: true, once: true});
 }
 
 // Load a given url in a given browser and fires the callback when it is loaded
 function loadAndWait(browser, url, callback) {
   listenOnce(browser, "load", callback);
   // We have to wait before calling `loadURI` otherwise, if we call
   // `loadAndWait` during browser load event, the history will be broken
   setTimeout(function () {
@@ -69,32 +68,31 @@ function loadAndWait(browser, url, callb
 // with a <browser> element loaded on a given content URL
 // The callback receive 3 arguments:
 // - test: reference to the jetpack test object
 // - browser: a reference to the <browser> xul node
 // - done: a callback to call when test is over
 function WorkerTest(url, callback) {
   return function testFunction(assert, done) {
     let chromeWindow = makeWindow();
-    chromeWindow.addEventListener("load", function onload() {
-      chromeWindow.removeEventListener("load", onload, true);
+    chromeWindow.addEventListener("load", function() {
       let browser = chromeWindow.document.createElement("browser");
       browser.setAttribute("type", "content");
       chromeWindow.document.documentElement.appendChild(browser);
       // Wait for about:blank load event ...
       listenOnce(browser, "load", function onAboutBlankLoad() {
         // ... before loading the expected doc and waiting for its load event
         loadAndWait(browser, url, function onDocumentLoaded() {
           callback(assert, browser, function onTestDone() {
 
             close(chromeWindow).then(done);
           });
         });
       });
-    }, true);
+    }, {capture: true, once: true});
   };
 }
 
 exports["test:sample"] = WorkerTest(
   DEFAULT_CONTENT_URL,
   function(assert, browser, done) {
 
     assert.notEqual(browser.contentWindow.location.href, "about:blank",
@@ -746,18 +744,17 @@ exports["test:check worker API with page
 
       // We have to wait before going back into history,
       // otherwise `goBack` won't do anything.
       setTimeout(function () {
         browser.goBack();
       }, 0);
 
       // Wait for the document to be hidden
-      browser.addEventListener("pagehide", function onpagehide() {
-        browser.removeEventListener("pagehide", onpagehide, false);
+      browser.addEventListener("pagehide", function() {
         // Now any event sent to this worker should throw
 
         assert.throws(
             function () { worker.postMessage("data"); },
             /The page is currently hidden and can no longer be used/,
             "postMessage should throw when the page is hidden in history"
             );
 
@@ -776,17 +773,17 @@ exports["test:check worker API with page
         setTimeout(function () {
           worker.on("message", function (data) {
             assert.ok(data, "timeout restored");
             done();
           });
           browser.goForward();
         }, 500);
 
-      }, false);
+      }, {once: true});
     });
 
   }
 );
 
 exports['test:conentScriptFile as URL instance'] = WorkerTest(
   DEFAULT_CONTENT_URL,
   function(assert, browser, done) {
--- a/addon-sdk/source/test/test-content-worker.js
+++ b/addon-sdk/source/test/test-content-worker.js
@@ -45,20 +45,19 @@ function makeWindow() {
 
   return Cc["@mozilla.org/embedcomp/window-watcher;1"].
          getService(Ci.nsIWindowWatcher).
          openWindow(null, url, null, features.join(","), null);
 }
 
 // Listen for only first one occurence of DOM event
 function listenOnce(node, eventName, callback) {
-  node.addEventListener(eventName, function onevent(event) {
-    node.removeEventListener(eventName, onevent, true);
+  node.addEventListener(eventName, function(event) {
     callback(node);
-  }, true);
+  }, {capture: true, once: true});
 }
 
 // Load a given url in a given browser and fires the callback when it is loaded
 function loadAndWait(browser, url, callback) {
   listenOnce(browser, "load", callback);
   // We have to wait before calling `loadURI` otherwise, if we call
   // `loadAndWait` during browser load event, the history will be broken
   setTimeout(function () {
@@ -70,32 +69,31 @@ function loadAndWait(browser, url, callb
 // with a <browser> element loaded on a given content URL
 // The callback receive 3 arguments:
 // - test: reference to the jetpack test object
 // - browser: a reference to the <browser> xul node
 // - done: a callback to call when test is over
 function WorkerTest(url, callback) {
   return function testFunction(assert, done) {
     let chromeWindow = makeWindow();
-    chromeWindow.addEventListener("load", function onload() {
-      chromeWindow.removeEventListener("load", onload, true);
+    chromeWindow.addEventListener("load", function() {
       let browser = chromeWindow.document.createElement("browser");
       browser.setAttribute("type", "content");
       chromeWindow.document.documentElement.appendChild(browser);
       // Wait for about:blank load event ...
       listenOnce(browser, "load", function onAboutBlankLoad() {
         // ... before loading the expected doc and waiting for its load event
         loadAndWait(browser, url, function onDocumentLoaded() {
           callback(assert, browser, function onTestDone() {
 
             close(chromeWindow).then(done);
           });
         });
       });
-    }, true);
+    }, {capture: true, once: true});
   };
 }
 
 exports["test:sample"] = WorkerTest(
   DEFAULT_CONTENT_URL,
   function(assert, browser, done) {
 
     assert.notEqual(browser.contentWindow.location.href, "about:blank",
@@ -763,18 +761,17 @@ exports["test:check worker API with page
 
       // We have to wait before going back into history,
       // otherwise `goBack` won't do anything.
       setTimeout(function () {
         browser.goBack();
       }, 0);
 
       // Wait for the document to be hidden
-      browser.addEventListener("pagehide", function onpagehide() {
-        browser.removeEventListener("pagehide", onpagehide, false);
+      browser.addEventListener("pagehide", function() {
         // Now any event sent to this worker should be cached
 
         worker.postMessage("message");
         worker.port.emit("event");
 
         // Display the page with attached content script back in order to resume
         // its timeout and receive the expected message.
         // We have to delay this in order to not break the history.
@@ -804,17 +801,17 @@ exports["test:check worker API with page
               })
             ]);
             promise.then(done);
           });
 
           browser.goForward();
         }, 500);
 
-      }, false);
+      }, {once: true});
     });
 
   }
 );
 
 exports['test:conentScriptFile as URL instance'] = WorkerTest(
   DEFAULT_CONTENT_URL,
   function(assert, browser, done) {
--- a/addon-sdk/source/test/test-context-menu.js
+++ b/addon-sdk/source/test/test-context-menu.js
@@ -303,17 +303,17 @@ exports.testSelectionContextInNewTab = f
     context: loader.cm.SelectionContext()
   });
 
   test.withTestDoc(function (window, doc) {
     let link = doc.getElementById("targetlink");
     link.click();
 
     let tablistener = event => {
-      this.tabBrowser.tabContainer.removeEventListener("TabOpen", tablistener, false);
+      this.tabBrowser.tabContainer.removeEventListener("TabOpen", tablistener);
       let tab = event.target;
       let browser = tab.linkedBrowser;
       this.loadFrameScript(browser);
       this.delayedEventListener(browser, "load", () => {
         let window = browser.contentWindow;
         let doc = browser.contentDocument;
         window.getSelection().selectAllChildren(doc.body);
 
@@ -326,17 +326,17 @@ exports.testSelectionContextInNewTab = f
 
           test.showMenu(null, function (popup) {
             test.checkMenu([item], [item], []);
             test.done();
           });
         });
       }, true);
     };
-    this.tabBrowser.tabContainer.addEventListener("TabOpen", tablistener, false);
+    this.tabBrowser.tabContainer.addEventListener("TabOpen", tablistener);
   });
 };
 
 
 // Selection contexts should work when right clicking a form button
 exports.testSelectionContextButtonMatch = function (assert, done) {
   let test = new TestHelper(assert, done);
   let loader = test.newLoader();
@@ -2626,17 +2626,17 @@ exports.testItemNoLabel = function (asse
   }
   catch (e) {
     assert.ok(true, "Should have seen exception");
   }
 
   test.done();
 }
 
-
+/* bug 1302854 - disabled this subtest as it is intermittent
 // Tests that items can have an empty data property
 exports.testItemNoData = function (assert, done) {
   let test = new TestHelper(assert, done);
   let loader = test.newLoader();
 
   function checkData(data) {
     assert.equal(data, undefined, "Data should be undefined");
   }
@@ -2681,16 +2681,17 @@ exports.testItemNoData = function (asser
 
             test.done();
           });
         });
       });
     });
   });
 }
+*/
 
 
 exports.testItemNoAccessKey = function (assert, done) {
   let test = new TestHelper(assert, done);
   let loader = test.newLoader();
 
   let item1 = new loader.cm.Item({ label: "item 1" });
   let item2 = new loader.cm.Item({ label: "item 2", accesskey: null });
--- a/addon-sdk/source/test/test-frame-utils.js
+++ b/addon-sdk/source/test/test-frame-utils.js
@@ -24,36 +24,34 @@ exports['test frame creation'] = functio
 };
 
 exports['test fram has js disabled by default'] = function(assert, done) {
   open('data:text/html;charset=utf-8,window').then(function (window) {
     let frame = create(window.document, {
       uri: 'data:text/html;charset=utf-8,<script>document.documentElement.innerHTML' +
            '= "J" + "S"</script>',
     });
-    frame.contentWindow.addEventListener('DOMContentLoaded', function ready() {
-      frame.contentWindow.removeEventListener('DOMContentLoaded', ready, false);
+    frame.contentWindow.addEventListener('DOMContentLoaded', function() {
       assert.ok(!~frame.contentDocument.documentElement.innerHTML.indexOf('JS'),
                 'JS was executed');
 
       close(window).then(done);
-    }, false);
+    }, {once: true});
   });
 };
 
 exports['test frame with js enabled'] = function(assert, done) {
   open('data:text/html;charset=utf-8,window').then(function (window) {
     let frame = create(window.document, {
       uri: 'data:text/html;charset=utf-8,<script>document.documentElement.innerHTML' +
            '= "J" + "S"</script>',
       allowJavascript: true
     });
-    frame.contentWindow.addEventListener('DOMContentLoaded', function ready() {
-      frame.contentWindow.removeEventListener('DOMContentLoaded', ready, false);
+    frame.contentWindow.addEventListener('DOMContentLoaded', function() {
       assert.ok(~frame.contentDocument.documentElement.innerHTML.indexOf('JS'),
                 'JS was executed');
 
       close(window).then(done);
-    }, false);
+    }, {once: true});
   });
 };
 
 require('sdk/test').run(exports);
--- a/addon-sdk/source/test/test-hidden-frame.js
+++ b/addon-sdk/source/test/test-hidden-frame.js
@@ -11,24 +11,23 @@ exports["test Frame"] = function(assert,
   let url = "data:text/html;charset=utf-8,<!DOCTYPE%20html>";
 
   let hiddenFrame = hiddenFrames.add(HiddenFrame({
     onReady: function () {
       assert.equal(this.element.contentWindow.location, "about:blank",
                        "HiddenFrame loads about:blank by default.");
 
       function onDOMReady() {
-        hiddenFrame.element.removeEventListener("DOMContentLoaded", onDOMReady,
-                                                false);
+        hiddenFrame.element.removeEventListener("DOMContentLoaded", onDOMReady);
         assert.equal(hiddenFrame.element.contentWindow.location, url,
                          "HiddenFrame loads the specified content.");
         done();
       }
 
-      this.element.addEventListener("DOMContentLoaded", onDOMReady, false);
+      this.element.addEventListener("DOMContentLoaded", onDOMReady);
       this.element.setAttribute("src", url);
     }
   }));
 };
 
 exports["test frame removed properly"] = function(assert, done) {
   let url = "data:text/html;charset=utf-8,<!DOCTYPE%20html>";
 
--- a/addon-sdk/source/test/test-l10n-locale.js
+++ b/addon-sdk/source/test/test-l10n-locale.js
@@ -105,18 +105,17 @@ exports.testPreferedContentLocale = func
   prefs.reset(PREF_ACCEPT_LANGUAGES);
 }
 
 exports.testPreferedOsLocale = function(assert) {
   prefs.set(PREF_MATCH_OS_LOCALE, true);
   prefs.set(PREF_SELECTED_LOCALE, "");
   prefs.set(PREF_ACCEPT_LANGUAGES, "");
 
-  let expectedLocale = Services.locale.getLocaleComponentForUserAgent().
-    toLowerCase();
+  let expectedLocale = Services.locale.getAppLocaleAsLangTag().toLowerCase();
   let expectedLocaleList = [expectedLocale];
 
   // Add default "en-us" fallback if the main language is not already en-us
   if (expectedLocale != "en-us")
     expectedLocaleList.push("en-us");
 
   assertPrefered(assert, expectedLocaleList, "Ensure that we select OS locale when related preference is set");
 
--- a/addon-sdk/source/test/test-page-mod.js
+++ b/addon-sdk/source/test/test-page-mod.js
@@ -417,17 +417,17 @@ exports.testCommunication2 = function*(a
     contentScript: 'new ' + function WorkerScope() {
       document.documentElement.setAttribute('AUQLUE', 42);
 
       window.addEventListener('load', function listener() {
         self.postMessage({
           msg: 'onload',
           AUQLUE: document.documentElement.getAttribute('AUQLUE')
         });
-      }, false);
+      });
 
       self.on("message", function(msg) {
         if (msg == "get window.test") {
           unsafeWindow.changesInWindow();
         }
 
         self.postMessage({
           msg: document.documentElement.getAttribute("test")
@@ -1022,54 +1022,51 @@ exports.testAttachToTabsOnly = function(
   });
 
   function openHiddenFrame() {
     assert.pass('Open iframe in hidden window');
     let hiddenFrames = require('sdk/frame/hidden-frame');
     let hiddenFrame = hiddenFrames.add(hiddenFrames.HiddenFrame({
       onReady: function () {
         let element = this.element;
-        element.addEventListener('DOMContentLoaded', function onload() {
-          element.removeEventListener('DOMContentLoaded', onload, false);
+        element.addEventListener('DOMContentLoaded', function() {
           hiddenFrames.remove(hiddenFrame);
 
           if (!xulApp.is("Fennec")) {
             openToplevelWindow();
           }
           else {
             openBrowserIframe();
           }
-        }, false);
+        }, {once: true});
         element.setAttribute('src', 'data:text/html;charset=utf-8,foo');
       }
     }));
   }
 
   function openToplevelWindow() {
     assert.pass('Open toplevel window');
     let win = open('data:text/html;charset=utf-8,bar');
-    win.addEventListener('DOMContentLoaded', function onload() {
-      win.removeEventListener('DOMContentLoaded', onload, false);
+    win.addEventListener('DOMContentLoaded', function() {
       win.close();
       openBrowserIframe();
-    }, false);
+    }, {once: true});
   }
 
   function openBrowserIframe() {
     assert.pass('Open iframe in browser window');
     let window = require('sdk/deprecated/window-utils').activeBrowserWindow;
     let document = window.document;
     let iframe = document.createElement('iframe');
     iframe.setAttribute('type', 'content');
     iframe.setAttribute('src', 'data:text/html;charset=utf-8,foobar');
-    iframe.addEventListener('DOMContentLoaded', function onload() {
-      iframe.removeEventListener('DOMContentLoaded', onload, false);
-      iframe.parentNode.removeChild(iframe);
+    iframe.addEventListener('DOMContentLoaded', function() {
+      iframe.remove();
       openTabWithIframes();
-    }, false);
+    }, {once: true});
     document.documentElement.appendChild(iframe);
   }
 
   // Only these three documents will be accepted by the page-mod
   function openTabWithIframes() {
     assert.pass('Open iframes in a tab');
     let subContent = '<iframe src="data:text/html;charset=utf-8,sub frame" />'
     let content = '<iframe src="data:text/html;charset=utf-8,' +
@@ -1581,17 +1578,17 @@ exports.testIFramePostMessage = function
   });
 };
 
 exports.testEvents = function*(assert) {
   let modAttached = defer();
   let content = "<script>\n new " + function DocumentScope() {
     window.addEventListener("ContentScriptEvent", function () {
       window.document.body.setAttribute("receivedEvent", "ok");
-    }, false);
+    });
   } + "\n</script>";
   let url = "data:text/html;charset=utf-8," + encodeURIComponent(content);
 
   let mod = PageMod({
     include: "data:*",
     contentScript: 'new ' + function WorkerScope() {
       let evt = document.createEvent("Event");
       evt.initEvent("ContentScriptEvent", true, true);
--- a/addon-sdk/source/test/test-system-events.js
+++ b/addon-sdk/source/test/test-system-events.js
@@ -142,17 +142,17 @@ exports["test alive listeners are remove
   assert.equal(receivedFromWeak.length, 1, "weak listener was removed");
   assert.equal(receivedFromStrong.length, 1, "strong listener was removed");
 };
 
 exports["test handle nsIObserverService notifications"] = function(assert) {
   let ios = Cc['@mozilla.org/network/io-service;1']
             .getService(Ci.nsIIOService);
 
-  let uri = ios.newURI("http://www.foo.com", null, null);
+  let uri = ios.newURI("http://www.foo.com");
 
   let type = Date.now().toString(32);
   let timesCalled = 0;
   let lastSubject = null;
   let lastData = null;
   let lastType = null;
 
   function handler({ subject, data, type }) {
@@ -206,17 +206,17 @@ exports["test handle nsIObserverService 
 
   assert.equal(timesCalled, 3, "* event handler is removed");
 };
 
 exports["test emit to nsIObserverService observers"] = function(assert) {
   let ios = Cc['@mozilla.org/network/io-service;1']
             .getService(Ci.nsIIOService);
 
-  let uri = ios.newURI("http://www.foo.com", null, null);
+  let uri = ios.newURI("http://www.foo.com");
   let timesCalled = 0;
   let lastSubject = null;
   let lastData = null;
   let lastTopic = null;
 
   var topic = Date.now().toString(32)
   let nsIObserver = {
     QueryInterface: function() {
--- a/addon-sdk/source/test/test-traceback.js
+++ b/addon-sdk/source/test/test-traceback.js
@@ -5,17 +5,17 @@
 
 var traceback = require("sdk/console/traceback");
 var {Cc,Ci,Cr,Cu} = require("chrome");
 const { on, off } = require("sdk/system/events");
 
 function throwNsIException() {
   var ios = Cc['@mozilla.org/network/io-service;1']
             .getService(Ci.nsIIOService);
-  ios.newURI("i'm a malformed URI", null, null);
+  ios.newURI("i'm a malformed URI");
 }
 
 function throwError() {
   throw new Error("foob");
 }
 
 exports.testFormatDoesNotFetchRemoteFiles = function(assert) {
   ["http", "https"].forEach(
--- a/addon-sdk/source/test/test-ui-action-button.js
+++ b/addon-sdk/source/test/test-ui-action-button.js
@@ -303,17 +303,17 @@ exports['test button global state update
   // Tried to use `getWidgetIdsInArea` but seems undefined, not sure if it
   // was removed or it's not in the UX build yet
 
   let { node, id: widgetId } = getWidget(button.id);
 
   // check read-only properties
 
   assert.throws(() => button.id = 'another-id',
-    /^setting a property that has only a getter/,
+    /^setting getter-only property/,
     'id cannot be set at runtime');
 
   assert.equal(button.id, 'my-button-4',
     'id is unchanged');
   assert.equal(node.id, widgetId,
     'node id is unchanged');
 
   // check writable properties
@@ -830,17 +830,17 @@ exports['test button icon set'] = functi
       '5': './icon5.png',
       '16': './icon16.png',
       '32': './icon32.png',
       '64': './icon64.png'
     }
   });
 
   let { node, id: widgetId } = getWidget(button.id);
-  let { devicePixelRatio } = node.ownerDocument.defaultView;
+  let { devicePixelRatio } = node.ownerGlobal;
 
   let size = 16 * devicePixelRatio;
 
   assert.equal(node.getAttribute('image'), data.url(button.icon[size].substr(2)),
     'the icon is set properly in navbar');
 
   size = 32 * devicePixelRatio;
 
@@ -1120,17 +1120,17 @@ exports['test button badge property'] = 
 
   assert.equal(button.badge, 123456,
     'badge is set');
 
   assert.equal(button.badgeColor, undefined,
     'badge color is not set');
 
   let { node } = getWidget(button.id);
-  let { getComputedStyle } = node.ownerDocument.defaultView;
+  let { getComputedStyle } = node.ownerGlobal;
   let badgeNode = badgeNodeFor(node);
 
   assert.equal('1234', node.getAttribute('badge'),
     'badge text is displayed up to four characters');
 
   assert.equal(getComputedStyle(badgeNode).backgroundColor, 'rgb(217, 0, 0)',
     'badge color is the default one');
 
@@ -1163,17 +1163,17 @@ exports['test button badge color'] = fun
     badge: '+1',
     badgeColor: 'blue'
   });
 
   assert.equal(button.badgeColor, 'blue',
     'badge color is set');
 
   let { node } = getWidget(button.id);
-  let { getComputedStyle } = node.ownerDocument.defaultView;
+  let { getComputedStyle } = node.ownerGlobal;
   let badgeNode = badgeNodeFor(node);
 
   assert.equal(badgeNodeFor(node).style.backgroundColor, 'blue',
     'badge color is displayed properly');
   assert.equal(getComputedStyle(badgeNode).backgroundColor, 'rgb(0, 0, 255)',
     'badge color overrides the default one');
 
   loader.unload();
--- a/addon-sdk/source/test/test-ui-sidebar.js
+++ b/addon-sdk/source/test/test-ui-sidebar.js
@@ -171,20 +171,20 @@ exports.testSideBarIsShowingInNewWindows
   assert.notEqual(startWindow, window, 'window is new');
 
   let sb = window.document.getElementById('sidebar');
   yield new Promise(resolve => {
     if (sb && sb.docShell && sb.contentDocument && sb.contentDocument.getElementById('web-panels-browser')) {
       end();
     }
     else {
-      sb.addEventListener('DOMWindowCreated', end, false);
+      sb.addEventListener('DOMWindowCreated', end);
     }
     function end () {
-      sb.removeEventListener('DOMWindowCreated', end, false);
+      sb.removeEventListener('DOMWindowCreated', end);
       resolve();
     }
   })
 
   ele = window.document.getElementById(makeID(testName));
   assert.ok(ele, 'sidebar element was added 2');
   assert.ok(isChecked(ele), 'the sidebar is checked');
   assert.notEqual(ele, oldEle, 'there are two different sidebars');
@@ -1045,17 +1045,17 @@ exports.testSidebarGettersAndSettersAfte
     url: url
   });
 
   sidebar.destroy();
 
   assert.equal(sidebar.id, undefined, 'sidebar after destroy has no id');
 
   assert.throws(() => sidebar.id = 'foo-tang',
-    /^setting a property that has only a getter/,
+    /^setting getter-only property/,
     'id cannot be set at runtime');
 
   assert.equal(sidebar.id, undefined, 'sidebar after destroy has no id');
 
   assert.equal(sidebar.title, undefined, 'sidebar after destroy has no title');
   sidebar.title = 'boo-tang';
   assert.equal(sidebar.title, undefined, 'sidebar after destroy has no title');
 
@@ -1090,20 +1090,19 @@ exports.testSidebarLeakCheckDestroyAfter
 
   sidebar.on('hide', () => {
     assert.fail('the sidebar hide listener should have been removed');
   });
   assert.pass('added a sidebar hide listener');
 
   yield new Promise(resolve => {
     let panelBrowser = window.document.getElementById('sidebar').contentDocument.getElementById('web-panels-browser');
-    panelBrowser.contentWindow.addEventListener('unload', function onUnload() {
-      panelBrowser.contentWindow.removeEventListener('unload', onUnload, false);
+    panelBrowser.contentWindow.addEventListener('unload', function() {
       resolve();
-    }, false);
+    }, {once: true});
     sidebar.destroy();
   });
 
   assert.pass('the sidebar web panel was unloaded properly');
 }
 
 exports.testSidebarLeakCheckUnloadAfterAttach = function*(assert) {
   const loader = Loader(module);
@@ -1132,20 +1131,19 @@ exports.testSidebarLeakCheckUnloadAfterA
 
   sidebar.on('hide', function() {
     assert.fail('the sidebar hide listener should have been removed');
   });
   assert.pass('added a sidebar hide listener');
 
   let panelBrowser = window.document.getElementById('sidebar').contentDocument.getElementById('web-panels-browser');
   yield new Promise(resolve => {
-    panelBrowser.contentWindow.addEventListener('unload', function onUnload() {
-      panelBrowser.contentWindow.removeEventListener('unload', onUnload, false);
+    panelBrowser.contentWindow.addEventListener('unload', function() {
       resolve();
-    }, false);
+    }, {once: true});
     loader.unload();
   });
 
   assert.pass('the sidebar web panel was unloaded properly');
 }
 
 exports.testTwoSidebarsWithSameTitleAndURL = function(assert) {
   const { Sidebar } = require('sdk/ui/sidebar');
--- a/addon-sdk/source/test/test-ui-toggle-button.js
+++ b/addon-sdk/source/test/test-ui-toggle-button.js
@@ -297,17 +297,17 @@ exports['test button global state update
   // Tried to use `getWidgetIdsInArea` but seems undefined, not sure if it
   // was removed or it's not in the UX build yet
 
   let { node, id: widgetId } = getWidget(button.id);
 
   // check read-only properties
 
   assert.throws(() => button.id = 'another-id',
-    /^setting a property that has only a getter/,
+    /^setting getter-only property/,
     'id cannot be set at runtime');
 
   assert.equal(button.id, 'my-button-4',
     'id is unchanged');
   assert.equal(node.id, widgetId,
     'node id is unchanged');
 
   // check writable properties
@@ -810,17 +810,17 @@ exports['test button icon set'] = functi
       '5': './icon5.png',
       '16': './icon16.png',
       '32': './icon32.png',
       '64': './icon64.png'
     }
   });
 
   let { node, id: widgetId } = getWidget(button.id);
-  let { devicePixelRatio } = node.ownerDocument.defaultView;
+  let { devicePixelRatio } = node.ownerGlobal;
 
   let size = 16 * devicePixelRatio;
 
   assert.equal(node.getAttribute('image'), data.url(button.icon[size].substr(2)),
     'the icon is set properly in navbar');
 
   size = 32 * devicePixelRatio;
 
@@ -1099,17 +1099,17 @@ exports['test button badge property'] = 
 
   assert.equal(button.badge, 123456,
     'badge is set');
 
   assert.equal(button.badgeColor, undefined,
     'badge color is not set');
 
   let { node } = getWidget(button.id);
-  let { getComputedStyle } = node.ownerDocument.defaultView;
+  let { getComputedStyle } = node.ownerGlobal;
   let badgeNode = badgeNodeFor(node);
 
   assert.equal('1234', node.getAttribute('badge'),
     'badge text is displayed up to four characters');
 
   assert.equal(getComputedStyle(badgeNode).backgroundColor, 'rgb(217, 0, 0)',
     'badge color is the default one');
 
@@ -1142,17 +1142,17 @@ exports['test button badge color'] = fun
     badge: '+1',
     badgeColor: 'blue'
   });
 
   assert.equal(button.badgeColor, 'blue',
     'badge color is set');
 
   let { node } = getWidget(button.id);
-  let { getComputedStyle } = node.ownerDocument.defaultView;
+  let { getComputedStyle } = node.ownerGlobal;
   let badgeNode = badgeNodeFor(node);
 
   assert.equal(badgeNodeFor(node).style.backgroundColor, 'blue',
     'badge color is displayed properly');
   assert.equal(getComputedStyle(badgeNode).backgroundColor, 'rgb(0, 0, 255)',
     'badge color overrides the default one');
 
   loader.unload();
--- a/addon-sdk/source/test/test-weak-set.js
+++ b/addon-sdk/source/test/test-weak-set.js
@@ -76,71 +76,71 @@ exports['test add/remove/iterate/clear i
 };
 
 exports['test adding non object or null item'] = function(assert) {
   let items = {};
 
   assert.throws(() => {
     add(items, 'foo');
   },
-  /^\w+ is not a non-null object/,
+  TypeError,
   'only non-null object are allowed');
 
   assert.throws(() => {
     add(items, 0);
   },
-  /^\w+ is not a non-null object/,
+  TypeError,
   'only non-null object are allowed');
 
   assert.throws(() => {
     add(items, undefined);
   },
-  /^\w+ is not a non-null object/,
+  TypeError,
   'only non-null object are allowed');
 
   assert.throws(() => {
     add(items, null);
   },
-  /^\w+ is not a non-null object/,
+  TypeError,
   'only non-null object are allowed');
 
   assert.throws(() => {
     add(items, true);
   },
-  /^\w+ is not a non-null object/,
+  TypeError,
   'only non-null object are allowed');
 };
 
 exports['test adding to non object or null item'] = function(assert) {
   let item = {};
 
   assert.throws(() => {
     add('foo', item);
   },
-  /^\w+ is not a non-null object/,
+  TypeError,
   'only non-null object are allowed');
 
   assert.throws(() => {
     add(0, item);
   },
-  /^\w+ is not a non-null object/,
+  TypeError,
   'only non-null object are allowed');
 
   assert.throws(() => {
     add(undefined, item);
   },
-  /^\w+ is not a non-null object/,
+  TypeError,
   'only non-null object are allowed');
 
   assert.throws(() => {
     add(null, item);
   },
-  /^\w+ is not a non-null object/,
+  TypeError,
   'only non-null object are allowed');
 
   assert.throws(() => {
     add(true, item);
   },
-  /^\w+ is not a non-null object/,
+  TypeError,
   'only non-null object are allowed');
 };
 
 require("sdk/test").run(exports);
--- a/addon-sdk/source/test/test-window-utils.js
+++ b/addon-sdk/source/test/test-window-utils.js
@@ -36,18 +36,17 @@ function makeEmptyWindow(options) {
     }
   });
 }
 
 exports.testWindowTracker = function(assert, done) {
   var myWindow = makeEmptyWindow();
   assert.pass('window was created');
 
-  myWindow.addEventListener("load", function onload() {
-    myWindow.removeEventListener("load", onload, false);
+  myWindow.addEventListener("load", function() {
     assert.pass("test window has opened");
 
     // test bug 638007 (new is optional), using new
     var wt = new windowUtils.WindowTracker({
       onTrack: window => {
         if (window === myWindow) {
           assert.pass("onTrack() called with our test window");
           close(window);
@@ -56,17 +55,17 @@ exports.testWindowTracker = function(ass
       onUntrack: window => {
         if (window === myWindow) {
           assert.pass("onUntrack() called with our test window");
           wt.unload();
           timer.setTimeout(done);
         }
       }
     });
-  }, false);
+  }, {once: true});
 };
 
 exports['test window watcher untracker'] = function(assert, done) {
   var myWindow;
   var tracks = 0;
   var unloadCalled = false;
 
   var delegate = {
@@ -143,20 +142,20 @@ exports['test window watcher unregs 4 lo
   // until the window loads, so we must let it load before closing it to be
   // certain that onTrack was removed.
   myWindow.addEventListener("load", function() {
     // allow all of the load handles to execute before closing
     myWindow.setTimeout(function() {
       myWindow.addEventListener("unload", function() {
         // once the window unloads test is done
         done();
-      }, false);
+      });
       myWindow.close();
     }, 0);
-  }, false);
+  });
 }
 
 exports['test window watcher without untracker'] = function(assert, done) {
   let myWindow;
   let wt = new windowUtils.WindowTracker({
     onTrack: function(window) {
       if (window == myWindow) {
         assert.pass("onTrack() called with our test window");
@@ -224,43 +223,43 @@ exports.testWindowIterator = function(as
       "window hasn't loaded yet.");
 
   // this window should only appear in windowIterator() while its loading
   assert.ok(toArray(windowUtils.windowIterator()).indexOf(window) === -1,
             "window isn't in windowIterator()");
 
   // Then it should be in windowIterator()
   window.addEventListener("load", function onload() {
-    window.addEventListener("load", onload, false);
+    window.addEventListener("load", onload);
     assert.ok(toArray(windowUtils.windowIterator()).indexOf(window) !== -1,
               "window is now in windowIterator()");
 
     // Wait for the window unload before ending test
     close(window).then(done);
-  }, false);
+  });
 };
 
 exports.testIgnoreClosingWindow = function(assert, done) {
   assert.equal(windows().length, 1, "Only one window open");
 
   // make a new window
   let window = makeEmptyWindow();
 
   assert.equal(windows().length, 2, "Two windows open");
 
   window.addEventListener("load", function onload() {
-    window.addEventListener("load", onload, false);
+    window.addEventListener("load", onload);
 
     assert.equal(windows().length, 2, "Two windows open");
 
     // Wait for the window unload before ending test
     let checked = false;
 
     close(window).then(function() {
       assert.ok(checked, 'the test is finished');
     }).then(done, assert.fail)
 
     assert.equal(windows().length, 1, "Only one window open");
     checked = true;
-  }, false);
+  });
 };
 
 require("sdk/test").run(exports);
--- a/addon-sdk/source/test/test-xhr.js
+++ b/addon-sdk/source/test/test-xhr.js
@@ -46,22 +46,21 @@ exports.testLocalXhr = function(assert, 
   req.overrideMimeType('text/plain');
   req.open('GET', data.url('testLocalXhr.json'));
   req.onreadystatechange = function() {
     if (req.readyState == 4 && (req.status == 0 || req.status == 200)) {
       ready = true;
       assert.equal(req.responseText, '{}\n', 'XMLHttpRequest should get local files');
     }
   };
-  req.addEventListener('load', function onload() {
-    req.removeEventListener('load', onload);
+  req.addEventListener('load', function() {
     assert.pass('addEventListener for load event worked');
     assert.ok(ready, 'onreadystatechange listener worked');
     done();
-  });
+  }, {once: true});
   req.send(null);
 };
 
 
 exports.testResponseHeaders = function(assert, done) {
   let req = new XMLHttpRequest();
 
   req.overrideMimeType('text/plain');
--- a/addon-sdk/source/test/test-xpcom.js
+++ b/addon-sdk/source/test/test-xpcom.js
@@ -136,18 +136,17 @@ function testRegister(assert, text) {
       get wrappedJSObject() {
         return this;
       },
       interfaces: [ 'nsIAboutModule' ],
       newChannel : function(aURI, aLoadInfo) {
         var ios = Cc["@mozilla.org/network/io-service;1"].
                   getService(Ci.nsIIOService);
 
-        var uri = ios.newURI("data:text/plain;charset=utf-8," + text,
-                             null, null);
+        var uri = ios.newURI("data:text/plain;charset=utf-8," + text);
         var channel = ios.newChannelFromURIWithLoadInfo(uri, aLoadInfo);
 
         channel.originalURI = aURI;
         return channel;
       },
       getURIFlags: function(aURI) {
         return Ci.nsIAboutModule.ALLOW_SCRIPT;
       }
@@ -159,17 +158,17 @@ function testRegister(assert, text) {
   assert.equal(isCIDRegistered(service.id), true);
 
   var aboutFactory = xpcom.factoryByContract(service.contract);
   var about = aboutFactory.createInstance(Ci.nsIAboutModule);
 
   var ios = Cc["@mozilla.org/network/io-service;1"].
             getService(Ci.nsIIOService);
   assert.equal(
-    about.getURIFlags(ios.newURI("http://foo.com", null, null)),
+    about.getURIFlags(ios.newURI("http://foo.com")),
     Ci.nsIAboutModule.ALLOW_SCRIPT
   );
 
   var channel = NetUtil.newChannel({
     uri: "about:boop",
     loadUsingSystemPrincipal: true
   });
   var iStream = channel.open2();
--- a/addon-sdk/test/browser.ini
+++ b/addon-sdk/test/browser.ini
@@ -2,13 +2,14 @@
 support-files =
   head.js
   Math.jsm
   math.js
   data.json
   invalid.json
 [browser_sdk_loader_sdk_modules.js]
 [browser_sdk_loader_sdk_gui_modules.js]
+skip-if = e10s # Bug 1315042
 [browser_sdk_loader_jsm_modules.js]
 [browser_sdk_loader_js_modules.js]
 [browser_sdk_loader_json.js]
 [browser_sdk_loader_chrome.js]
 [browser_sdk_loader_chrome_in_sdk.js]
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -273,17 +273,16 @@ pref("ui.graytext", "#b1a598");
 pref("ui.highlighttext", "#1a1a1a");
 pref("ui.threeddarkshadow", "#000");
 pref("ui.threedface", "#ece7e2");
 pref("ui.threedhighlight", "#fff");
 pref("ui.threedlightshadow", "#ece7e2");
 pref("ui.threedshadow", "#aea194");
 pref("ui.windowframe", "#efebe7");
 
-// Themable via mozSettings
 pref("ui.menu", "#f97c17");
 pref("ui.menutext", "#ffffff");
 pref("ui.infobackground", "#343e40");
 pref("ui.infotext", "#686868");
 pref("ui.window", "#ffffff");
 pref("ui.windowtext", "#000000");
 pref("ui.highlight", "#b2f2ff");
 
@@ -320,17 +319,16 @@ pref("media.cache_readahead_limit", 30);
 
 #ifdef MOZ_FMP4
 // Enable/Disable Gonk Decoder Module
 pref("media.gonk.enabled", true);
 #endif
 
 //Encrypted media extensions.
 pref("media.eme.enabled", true);
-pref("media.eme.apiVisible", true);
 // The default number of decoded video frames that are enqueued in
 // MediaDecoderReader's mVideoQueue.
 pref("media.video-queue.default-size", 3);
 
 // optimize images' memory usage
 pref("image.downscale-during-decode.enabled", true);
 pref("image.mem.allow_locking_in_content_processes", true);
 // Limit the surface cache to 1/8 of main memory or 128MB, whichever is smaller.
@@ -404,19 +402,16 @@ pref("dom.phonenumber.substringmatching.
 pref("dom.webapps.firstRunWithSIM", true);
 #endif
 
 #ifdef MOZ_B2G_RIL
 // SingleVariant
 pref("dom.mozApps.single_variant_sourcedir", "/persist/svoperapps");
 #endif
 
-// WebSettings
-pref("dom.mozSettings.enabled", true);
-
 // controls if we want camera support
 pref("device.camera.enabled", true);
 pref("media.realtime_decoder.enabled", true);
 
 // TCPSocket
 pref("dom.mozTCPSocket.enabled", true);
 
 // "Preview" landing of bug 710563, which is bogged down in analysis
@@ -889,19 +884,16 @@ pref("dom.apps.reviewer_paths", "/review
 
 //