Merge m-c -> b-i
authorGregor Wagner <gwagner@mozilla.com>
Mon, 08 Feb 2016 14:41:52 +0100
changeset 325499 a3d54e32dee1d0f95a424f2df406ab23e50bf241
parent 325498 beea9ac7d82391a03247940e2a1e9ee0f7d44940 (current diff)
parent 319768 ac338559876df7b2e81388f2aac28d2e95ceb5ff (diff)
child 325500 064938420fc838d9040c45e0ec82eb1c9b7bf5b1
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c -> b-i
b2g/branding/browserhtml/Makefile.in
b2g/branding/horizon/Makefile.in
b2g/branding/official/Makefile.in
b2g/branding/unofficial/Makefile.in
b2g/config/aries-l/sources.xml
b2g/config/aries/sources.xml
b2g/config/dolphin/sources.xml
b2g/config/emulator-ics/sources.xml
b2g/config/emulator-jb/sources.xml
b2g/config/emulator-kk/sources.xml
b2g/config/emulator-l/sources.xml
b2g/config/emulator/sources.xml
b2g/config/flame-kk/sources.xml
b2g/config/gaia.json
b2g/config/nexus-4-kk/sources.xml
b2g/config/nexus-4/sources.xml
b2g/config/nexus-5-l/sources.xml
browser/base/content/test/newtab/browser_newtab_external_resource.js
browser/base/content/test/newtab/external_newtab.html
browser/base/content/test/social/microdata.html
browser/extensions/loop/chrome/content/panels/test/README.md
browser/extensions/loop/chrome/content/shared/README.md
browser/extensions/loop/chrome/skin/windows/toolbar-win10.png
browser/extensions/loop/chrome/skin/windows/toolbar-win10@2x.png
browser/fuel/fuelApplication.js
browser/fuel/fuelApplication.manifest
browser/fuel/fuelIApplication.idl
browser/fuel/moz.build
browser/fuel/test/.eslintrc
browser/fuel/test/ContentA.html
browser/fuel/test/ContentB.html
browser/fuel/test/ContentWithFrames.html
browser/fuel/test/browser.ini
browser/fuel/test/browser_Application.js
browser/fuel/test/browser_ApplicationPrefs.js
browser/fuel/test/browser_ApplicationQuitting.js
browser/fuel/test/browser_ApplicationStorage.js
browser/fuel/test/browser_Bookmarks.js
browser/fuel/test/browser_Browser.js
browser/modules/SignInToWebsite.jsm
browser/modules/test/browser_SignInToWebsite.js
build/macosx/mozconfig.rust
build/stlport/Makefile.in
build/unix/mozconfig.rust
config/external/nspr/Makefile.in
devtools/client/inspector/computed/computed.xhtml
devtools/client/inspector/fonts/fonts.xhtml
devtools/client/inspector/layout/layout.xhtml
devtools/client/inspector/markup/markup.css
devtools/client/inspector/rules/rules.xhtml
devtools/client/inspector/test/browser_inspector_highlighter-iframes.js
devtools/client/memory/test/browser/browser_memory-breakdowns-01.js
devtools/client/memory/test/browser/browser_memory-clear-snapshots.js
devtools/client/memory/test/browser/browser_memory-simple-01.js
devtools/client/performance/test/browser_perf-telemetry.js
devtools/client/performance/views/optimizations-list.js
devtools/client/promisedebugger/test/browser.ini
devtools/client/sourceeditor/codemirror/lib/codemirror.js
devtools/client/sourceeditor/codemirror/mode/clike.js
devtools/client/sourceeditor/codemirror/mode/css.js
devtools/client/sourceeditor/codemirror/mode/javascript.js
devtools/client/sourceeditor/test/codemirror/mode_test.js
devtools/client/sourceeditor/test/codemirror/test.js
devtools/client/themes/images/debugger-toggleBreakpoints.png
devtools/client/themes/images/debugger-toggleBreakpoints@2x.png
devtools/client/themes/images/editor-breakpoint.png
devtools/client/themes/images/editor-breakpoint@2x.png
devtools/client/themes/images/editor-debug-location.png
devtools/client/themes/images/editor-debug-location@2x.png
devtools/shared/apps/tests/data/mochitest.ini
docshell/test/chrome/mochitest.ini
dom/base/Makefile.in
dom/base/test/chrome/mochitest.ini
dom/base/test/empty_worker.js
dom/base/test/test_performance_translate.html
dom/imptests/mochitest.ini
dom/interfaces/events/nsIDOMCompositionEvent.idl
dom/interfaces/events/nsIDOMMessageEvent.idl
dom/media/webaudio/test/audioBufferSourceNodeNeutered_worker.js
dom/media/webaudio/test/blink/mochitest.ini
dom/media/webaudio/test/test_audioBufferSourceNodeNeutered.html
dom/network/interfaces/nsIDOMNetworkStatsManager.idl
dom/payment/interfaces/nsINavigatorPayment.idl
dom/tests/mochitest/ajax/lib/mochitest.ini
dom/tests/mochitest/ajax/mochikit/tests/mochitest.ini
dom/tests/mochitest/webapps/apps/bad_content_type.webapp
dom/tests/mochitest/webapps/apps/basic.webapp
dom/tests/mochitest/webapps/apps/basic.webapp^headers^
dom/tests/mochitest/webapps/apps/installs_allowed_from_chrome_mochitests.webapp
dom/tests/mochitest/webapps/apps/installs_allowed_from_chrome_mochitests.webapp^headers^
dom/tests/mochitest/webapps/apps/installs_allowed_from_example.com.webapp
dom/tests/mochitest/webapps/apps/installs_allowed_from_example.com.webapp^headers^
dom/tests/mochitest/webapps/apps/invalid_activity_href.webapp
dom/tests/mochitest/webapps/apps/invalid_activity_href.webapp^headers^
dom/tests/mochitest/webapps/apps/invalid_activity_href2.webapp
dom/tests/mochitest/webapps/apps/invalid_activity_href2.webapp^headers^
dom/tests/mochitest/webapps/apps/invalid_entry_point.webapp
dom/tests/mochitest/webapps/apps/invalid_entry_point.webapp^headers^
dom/tests/mochitest/webapps/apps/invalid_launch_path.webapp
dom/tests/mochitest/webapps/apps/invalid_launch_path.webapp^headers^
dom/tests/mochitest/webapps/apps/invalid_launch_path2.webapp
dom/tests/mochitest/webapps/apps/invalid_launch_path2.webapp^headers^
dom/tests/mochitest/webapps/apps/invalid_locale_entry_point.webapp
dom/tests/mochitest/webapps/apps/invalid_locale_entry_point.webapp^headers^
dom/tests/mochitest/webapps/apps/invalid_message.webapp
dom/tests/mochitest/webapps/apps/invalid_message.webapp^headers^
dom/tests/mochitest/webapps/apps/json_syntax_error.webapp
dom/tests/mochitest/webapps/apps/json_syntax_error.webapp^headers^
dom/tests/mochitest/webapps/apps/launch_paths.webapp
dom/tests/mochitest/webapps/apps/launch_paths.webapp^headers^
dom/tests/mochitest/webapps/apps/missing_required_field.webapp
dom/tests/mochitest/webapps/apps/missing_required_field.webapp^headers^
dom/tests/mochitest/webapps/apps/no_delegated_install.webapp
dom/tests/mochitest/webapps/apps/no_delegated_install.webapp^headers^
dom/tests/mochitest/webapps/apps/utf8.webapp
dom/tests/mochitest/webapps/apps/utf8.webapp^headers^
dom/tests/mochitest/webapps/chrome.ini
dom/tests/mochitest/webapps/cross_origin.html
dom/tests/mochitest/webapps/file_bug_779982.html
dom/tests/mochitest/webapps/file_bug_779982.js
dom/tests/mochitest/webapps/head.js
dom/tests/mochitest/webapps/install_and_redirect_helper.xul
dom/tests/mochitest/webapps/mochitest.ini
dom/tests/mochitest/webapps/test_bug_765063.xul
dom/tests/mochitest/webapps/test_bug_771294.xul
dom/tests/mochitest/webapps/test_bug_779982.html
dom/tests/mochitest/webapps/test_cross_origin.xul
dom/tests/mochitest/webapps/test_getNotInstalled.xul
dom/tests/mochitest/webapps/test_install_app.xul
dom/tests/mochitest/webapps/test_install_errors.xul
dom/tests/mochitest/webapps/test_install_utf8.xul
dom/tests/mochitest/webapps/test_launch_paths.xul
dom/tests/mochitest/webapps/test_list_api.xul
dom/workers/test/serviceworkers/app-protocol/README.txt
dom/workers/test/serviceworkers/app-protocol/application.list
dom/workers/test/serviceworkers/app-protocol/application.zip
dom/workers/test/serviceworkers/app-protocol/controlled.html
dom/workers/test/serviceworkers/app-protocol/foo.txt
dom/workers/test/serviceworkers/app-protocol/index.html
dom/workers/test/serviceworkers/app-protocol/makezip.sh
dom/workers/test/serviceworkers/app-protocol/manifest.webapp
dom/workers/test/serviceworkers/app-protocol/realindex.html
dom/workers/test/serviceworkers/app-protocol/realindex.html^headers^
dom/workers/test/serviceworkers/app-protocol/redirect-https.sjs
dom/workers/test/serviceworkers/app-protocol/redirect.sjs
dom/workers/test/serviceworkers/app-protocol/sw.js
dom/workers/test/serviceworkers/app-protocol/test.js
dom/workers/test/serviceworkers/app-protocol/test_doc_load_interception.js
dom/workers/test/serviceworkers/app-protocol/unregister.html
dom/workers/test/serviceworkers/app-protocol/update.webapp
dom/workers/test/serviceworkers/app-protocol/update.webapp^headers^
dom/workers/test/serviceworkers/app/index.html
dom/workers/test/serviceworkers/app/manifest.webapp
dom/workers/test/serviceworkers/app/manifest.webapp^headers^
dom/workers/test/serviceworkers/app/sw.js
dom/workers/test/serviceworkers/app2/client.html
dom/workers/test/serviceworkers/app2/index.html
dom/workers/test/serviceworkers/app2/manifest.webapp
dom/workers/test/serviceworkers/app2/manifest.webapp^headers^
dom/workers/test/serviceworkers/app2/sw.sjs
dom/workers/test/serviceworkers/app2/version.html
dom/workers/test/serviceworkers/app2/wait_for_update.html
dom/workers/test/serviceworkers/app3/index.html
dom/workers/test/serviceworkers/app3/manifest.webapp
dom/workers/test/serviceworkers/app3/manifest.webapp^headers^
dom/workers/test/serviceworkers/download_window.html
dom/workers/test/serviceworkers/download_worker.js
dom/workers/test/serviceworkers/test_aboutserviceworkers.html
dom/workers/test/serviceworkers/test_app_installation.html
dom/workers/test/serviceworkers/test_app_protocol.html
dom/workers/test/serviceworkers/test_clear_origin_data.html
gfx/ots/src/woff2.cc
gfx/ots/src/woff2.h
gfx/skia/Makefile.in
js/src/tests/ecma_6/extensions/ArrayBuffer-slice-arguments-neutering.js
js/src/tests/ecma_6/extensions/DataView-construct-arguments-neutering.js
js/src/tests/ecma_6/extensions/DataView-set-arguments-neutering.js
js/src/tests/ecma_6/extensions/TypedArray-set-object-funky-length-neuters.js
js/src/tests/ecma_6/extensions/TypedArray-subarray-arguments-neutering.js
js/src/tests/ecma_6/extensions/element-setting-ToNumber-neuters.js
js/src/tests/js1_8_5/extensions/typedarray-copyWithin-arguments-neutering.js
js/xpconnect/tests/chrome/mochitest.ini
js/xpconnect/tests/xpcshell.ini
layout/reftests/fonts/math/mochitest.ini
layout/reftests/fonts/mochitest.ini
layout/reftests/fonts/mplus/mochitest.ini
layout/style/test/chrome/mochitest.ini
layout/style/test/css-visited/mochitest.ini
media/libstagefright/binding/MP4Metadata.rs
media/libstagefright/binding/byteorder/mod.rs
media/libstagefright/binding/byteorder/new.rs
media/libstagefright/binding/capi.rs
media/omx-plugin/lib/ics/libvideoeditorplayer/Makefile.in
mobile/android/base/docs/index.rst
mobile/android/base/java/org/mozilla/gecko/widget/FloatingHintEditText.java
mobile/android/base/resources/drawable-hdpi/network_offline.png
mobile/android/base/resources/drawable-xhdpi/network_offline.png
mobile/android/config/mozconfigs/android-api-11/debug
mobile/android/config/mozconfigs/android-api-11/l10n-nightly
mobile/android/config/mozconfigs/android-api-11/l10n-release
mobile/android/config/mozconfigs/android-api-11/nightly
mobile/android/config/mozconfigs/android-api-11/release
mobile/android/docs/gradle.rst
mobile/android/services/src/main/res/layout/sync_account.xml
mobile/android/services/src/main/res/layout/sync_list_item.xml
mobile/android/services/src/main/res/layout/sync_redirect_to_setup.xml
mobile/android/services/src/main/res/layout/sync_send_tab.xml
mobile/android/services/src/main/res/layout/sync_setup.xml
mobile/android/services/src/main/res/layout/sync_setup_failure.xml
mobile/android/services/src/main/res/layout/sync_setup_jpake_waiting.xml
mobile/android/services/src/main/res/layout/sync_setup_nointernet.xml
mobile/android/services/src/main/res/layout/sync_setup_pair.xml
mobile/android/services/src/main/res/layout/sync_setup_success.xml
mobile/android/services/src/main/res/layout/sync_setup_webview.xml
mobile/android/services/src/main/res/values-large-v11/sync_styles.xml
mobile/android/services/src/main/res/values-v11/sync_styles.xml
mobile/android/services/src/main/res/values/sync_styles.xml
mobile/android/tests/browser/robocop/roboextender/base/SelectionUtils.js
mobile/android/tests/browser/robocop/roboextender/base/testInputSelections.html
mobile/android/tests/browser/robocop/roboextender/base/testSelectionHandler.html
mobile/android/tests/browser/robocop/roboextender/base/testTextareaSelections.html
mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputSelections.java
mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testSelectionHandler.java
mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testTextareaSelections.java
modules/libjar/InterceptedJARChannel.cpp
modules/libjar/InterceptedJARChannel.h
parser/htmlparser/tests/mochitest/test_viewsource.html
python/virtualenv/virtualenv_support/pip-6.0.6-py2.py3-none-any.whl
python/virtualenv/virtualenv_support/setuptools-11.0-py2.py3-none-any.whl
services/common/bagheeraclient.js
services/common/modules-testing/bagheeraserver.js
services/common/tests/run_bagheera_server.js
services/common/tests/unit/test_bagheera_client.js
services/common/tests/unit/test_bagheera_server.js
testing/docker/desktop-build/REGISTRY
testing/docker/desktop-build/VERSION
testing/docker/desktop-test/REGISTRY
testing/docker/desktop-test/VERSION
testing/docker/tester/b2g-desktop-config.py
testing/docker/tester/buildprops.json
testing/docker/tester/mozharness_configs/emulator_override.py
testing/docker/tester/mozharness_configs/gaia_integration_override.py
testing/docker/tester/mozharness_configs/remove_executables.py
testing/marionette/transport/marionette_transport/__init__.py
testing/marionette/transport/marionette_transport/transport.py
testing/marionette/transport/setup.py
testing/mochitest/MochiKit/mochitest.ini
testing/mochitest/dynamic/mochitest.ini
testing/mochitest/manifests/Makefile.in
testing/mochitest/static/mochitest.ini
testing/mochitest/tests/MochiKit-1.4.2/MochiKit/mochitest.ini
testing/mozharness/configs/b2g/desktop_automation_config.py
testing/mozharness/configs/b2g/emulator_test_config.py
testing/mozharness/configs/b2g/gaia_integration_config.py
testing/mozharness/configs/b2g/gaia_unit_production_config.py
testing/mozharness/configs/b2g/generic_config.py
testing/mozharness/configs/b2g/mulet_config.py
testing/mozharness/external_tools/purge_builds.py
testing/specialpowers/content/MockPaymentsUIGlue.jsm
testing/web-platform/meta/cssom-view/elementsFromPoint.html.ini
testing/web-platform/meta/html/semantics/grouping-content/the-pre-element/pre-newline-bidi.html.ini
testing/web-platform/meta/html/semantics/text-level-semantics/the-bdi-element/bdi-neutral-wrapped.html.ini
testing/web-platform/meta/selectors/attribute-selectors/attribute-case/semantics.html.ini
testing/web-platform/meta/selectors/attribute-selectors/attribute-case/syntax.html.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/fetch-request-resources.https.html.ini
testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/001.html
testing/web-platform/tests/workers/interfaces/WorkerUtils/importScripts/002.html
toolkit/components/jsdownloads/test/data/xpcshell.ini
toolkit/components/places/tests/browser/mochitest.ini
toolkit/components/places/tests/chrome/mochitest.ini
toolkit/components/places/tests/mochitest.ini
toolkit/components/places/tests/mochitest/bug_411966/mochitest.ini
toolkit/components/places/tests/mochitest/bug_461710/mochitest.ini
toolkit/components/places/tests/xpcshell.ini
toolkit/content/aboutwebrtc/aboutWebrtc.xhtml
toolkit/crashreporter/google-breakpad/src/client/linux/handler/Makefile.in
toolkit/locales/en-US/chrome/mozapps/extensions/selectAddons.dtd
toolkit/locales/en-US/chrome/mozapps/extensions/selectAddons.properties
toolkit/mozapps/extensions/content/selectAddons.css
toolkit/mozapps/extensions/content/selectAddons.js
toolkit/mozapps/extensions/content/selectAddons.xml
toolkit/mozapps/extensions/content/selectAddons.xul
toolkit/mozapps/extensions/test/browser/addons/browser_select_compatoverrides_1/install.rdf
toolkit/mozapps/extensions/test/browser/browser_select_compatoverrides.js
toolkit/mozapps/extensions/test/browser/browser_select_compatoverrides.xml
toolkit/mozapps/extensions/test/browser/browser_select_confirm.js
toolkit/mozapps/extensions/test/browser/browser_select_selection.js
toolkit/mozapps/extensions/test/browser/browser_select_update.js
toolkit/mozapps/extensions/test/xpcshell/test_bug596343.js
toolkit/themes/linux/mozapps/extensions/selectAddons.css
toolkit/themes/osx/global/icons/searchfield-regular-cancel.png
toolkit/themes/osx/global/icons/searchfield-small-cancel.png
toolkit/themes/osx/mozapps/extensions/selectAddons.css
toolkit/themes/windows/mozapps/extensions/selectAddons.css
widget/gonk/nativewindow/GonkNativeWindowClient.h
widget/gonk/nativewindow/GonkNativeWindowClientICS.cpp
widget/gonk/nativewindow/GonkNativeWindowClientICS.h
widget/gonk/nativewindow/GonkNativeWindowClientJB.cpp
widget/gonk/nativewindow/GonkNativeWindowClientJB.h
widget/gonk/nativewindow/GonkNativeWindowClientKK.cpp
widget/gonk/nativewindow/GonkNativeWindowClientKK.h
widget/gonk/nativewindow/GonkNativeWindowClientLL.cpp
widget/gonk/nativewindow/GonkNativeWindowClientLL.h
--- a/.eslintignore
+++ b/.eslintignore
@@ -34,18 +34,16 @@ modules/**
 mozglue/**
 netwerk/**
 nsprpub/**
 other-licenses/**
 parser/**
 probes/**
 python/**
 rdf/**
-security/**
-services/**
 startupcache/**
 testing/**
 tools/**
 uriloader/**
 view/**
 webapprt/**
 widget/**
 xpcom/**
@@ -72,55 +70,51 @@ browser/components/preferences/**
 browser/components/privatebrowsing/**
 browser/components/sessionstore/**
 browser/components/shell/**
 browser/components/tabview/**
 browser/components/translation/**
 browser/extensions/pdfjs/**
 browser/extensions/pocket/content/panels/js/vendor/**
 browser/extensions/shumway/**
-browser/fuel/**
 browser/locales/**
 
 # Ignore all of loop since it is imported from github and checked at source.
 browser/extensions/loop/**
 
 # devtools/ exclusions
 devtools/*.js
-devtools/client/*.js
-devtools/client/aboutdebugging/**
 devtools/client/animationinspector/**
 devtools/client/canvasdebugger/**
 devtools/client/commandline/**
 devtools/client/debugger/**
 devtools/client/eyedropper/**
 devtools/client/framework/**
 # devtools/client/inspector/shared/*.js files are eslint-clean, so they aren't
 # included in the ignore list.
 devtools/client/inspector/computed/**
 devtools/client/inspector/fonts/**
 devtools/client/inspector/layout/**
-devtools/client/inspector/markup/**
+devtools/client/inspector/markup/test/**
 devtools/client/inspector/rules/**
 devtools/client/inspector/shared/test/**
 devtools/client/inspector/test/**
 devtools/client/inspector/*.js
 devtools/client/jsonview/**
 devtools/client/memory/**
 devtools/client/netmonitor/**
 devtools/client/performance/**
 devtools/client/projecteditor/**
 devtools/client/promisedebugger/**
 devtools/client/responsivedesign/**
 devtools/client/scratchpad/**
 devtools/client/shadereditor/**
 devtools/client/shared/**
 devtools/client/sourceeditor/**
 devtools/client/storage/**
-devtools/client/styleeditor/**
 devtools/client/tilt/**
 devtools/client/webaudioeditor/**
 devtools/client/webconsole/**
 devtools/client/webide/**
 devtools/server/**
 devtools/shared/**
 
 # Ignore devtools pre-processed files
@@ -169,16 +163,21 @@ mobile/android/modules/ContactService.js
 mobile/android/modules/WebappManager.jsm
 
 # Non-standard `(catch ex if ...)`
 mobile/android/components/Snippets.js
 
 # Bug 1178739: Ignore this file as a quick fix for "Illegal yield expression"
 mobile/android/modules/HomeProvider.jsm
 
+# services/ exclusions
+
+# Uses `#filter substitution`
+services/sync/modules/constants.js
+
 # toolkit/ exclusions
 
 # Not part of the default build
 toolkit/components/help/**
 
 # Intentionally invalid JS
 toolkit/components/workerloader/tests/moduleF-syntax-error.js
 
--- a/.gitignore
+++ b/.gitignore
@@ -5,16 +5,19 @@
 *.pyc
 *.pyo
 TAGS
 tags
 ID
 .DS_Store*
 *.pdb
 
+# Allow the id locale directory for loop ('ID' matches this normally)
+!browser/extensions/loop/chrome/locale/id
+
 # Vim swap files.
 .*.sw[a-z]
 
 # Emacs directory variable files.
 **/.dir-locals.el
 
 # User files that may appear at the root
 /.mozconfig*
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,10 +17,10 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
+Bug 1237983 - Investigate and remove the Bagheera Client implementation.
 
-Merge day clobber
\ No newline at end of file
--- a/Makefile.in
+++ b/Makefile.in
@@ -109,17 +109,19 @@ backend: $(BUILD_BACKEND_FILES)
 $(subst .,%,$(BUILD_BACKEND_FILES)):
 	@echo 'Build configuration changed. Regenerating backend.'
 	$(PYTHON) config.status
 
 Makefile: $(BUILD_BACKEND_FILES)
 	@$(TOUCH) $@
 
 define build_backend_rule
-$(1): $$(shell cat $(1).in)
+$(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 := \
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -140,17 +140,17 @@ MaiAtkObject::GetAtkHyperlink()
   }
 
   return maiHyperlink->GetAtkHyperlink();
 }
 
 void
 MaiAtkObject::Shutdown()
 {
-  accWrap = 0;
+  accWrap.SetBits(0);
   MaiHyperlink* maiHyperlink =
     (MaiHyperlink*)g_object_get_qdata(G_OBJECT(this), quark_mai_hyperlink);
   if (maiHyperlink) {
     delete maiHyperlink;
     g_object_set_qdata(G_OBJECT(this), quark_mai_hyperlink, nullptr);
   }
 }
 
@@ -554,25 +554,25 @@ initializeCB(AtkObject *aAtkObj, gpointe
     /* AtkObjectClass has not a "initialize" function now,
      * maybe it has later
      */
 
     if (ATK_OBJECT_CLASS(parent_class)->initialize)
         ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData);
 
   /* initialize object */
-  MAI_ATK_OBJECT(aAtkObj)->accWrap = reinterpret_cast<uintptr_t>(aData);
+  MAI_ATK_OBJECT(aAtkObj)->accWrap.SetBits(reinterpret_cast<uintptr_t>(aData));
 }
 
 void
 finalizeCB(GObject *aObj)
 {
     if (!IS_MAI_OBJECT(aObj))
         return;
-    NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == 0, "AccWrap NOT null");
+    NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap.IsNull(), "AccWrap NOT null");
 
     // call parent finalize function
     // finalize of GObjectClass will unref the accessible parent if has
     if (G_OBJECT_CLASS (parent_class)->finalize)
         G_OBJECT_CLASS (parent_class)->finalize(aObj);
 }
 
 const gchar*
@@ -645,40 +645,35 @@ getDescriptionCB(AtkObject *aAtkObj)
 }
 
 AtkRole
 getRoleCB(AtkObject *aAtkObj)
 {
   if (aAtkObj->role != ATK_ROLE_INVALID)
     return aAtkObj->role;
 
-  AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
-  a11y::role role;
-  if (!accWrap) {
-    ProxyAccessible* proxy = GetProxy(aAtkObj);
-    if (!proxy)
-      return ATK_ROLE_INVALID;
+  AccessibleOrProxy acc = GetInternalObj(aAtkObj);
+  if (acc.IsNull()) {
+    return ATK_ROLE_INVALID;
+  }
 
-    role = proxy->Role();
-  } else {
 #ifdef DEBUG
+  if (AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj)) {
     NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
                  "Does not support Text interface when it should");
+  }
 #endif
 
-    role = accWrap->Role();
-  }
-
 #define ROLE(geckoRole, stringRole, atkRole, macRole, \
              msaaRole, ia2Role, nameRule) \
   case roles::geckoRole: \
     aAtkObj->role = atkRole; \
     break;
 
-  switch (role) {
+  switch (acc.Role()) {
 #include "RoleMap.h"
     default:
       MOZ_CRASH("Unknown role.");
   }
 
 #undef ROLE
 
   if (aAtkObj->role == ATK_ROLE_LIST_BOX && !IsAtkVersionAtLeast(2, 1))
@@ -759,17 +754,17 @@ getAttributesCB(AtkObject *aAtkObj)
   AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
   if (accWrap)
     return GetAttributeSet(accWrap);
 
   ProxyAccessible* proxy = GetProxy(aAtkObj);
   if (!proxy)
     return nullptr;
 
-  nsAutoTArray<Attribute, 10> attrs;
+  AutoTArray<Attribute, 10> attrs;
   proxy->Attributes(&attrs);
   if (attrs.IsEmpty())
     return nullptr;
 
   AtkAttributeSet* objAttributeSet = nullptr;
   for (uint32_t i = 0; i < attrs.Length(); i++) {
     AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
     objAttr->name = g_strdup(attrs[i].Name().get());
@@ -1019,17 +1014,17 @@ refRelationSetCB(AtkObject *aAtkObj)
     proxy->Relations(&types, &targetSets);
 
     size_t relationCount = types.Length();
     for (size_t i = 0; i < relationCount; i++) {
       if (typeMap[static_cast<uint32_t>(types[i])] == ATK_RELATION_NULL)
         continue;
 
       size_t targetCount = targetSets[i].Length();
-      nsAutoTArray<AtkObject*, 5> wrappers;
+      AutoTArray<AtkObject*, 5> wrappers;
       for (size_t j = 0; j < targetCount; j++)
         wrappers.AppendElement(GetWrapperFor(targetSets[i][j]));
 
       AtkRelationType atkType = typeMap[static_cast<uint32_t>(types[i])];
       AtkRelation* atkRelation =
         atk_relation_set_get_relation_by_type(relation_set, atkType);
       if (atkRelation)
         atk_relation_set_remove(relation_set, atkRelation);
@@ -1059,23 +1054,23 @@ refRelationSetCB(AtkObject *aAtkObj)
 // for it.
 AccessibleWrap*
 GetAccessibleWrap(AtkObject* aAtkObj)
 {
   bool isMAIObject = IS_MAI_OBJECT(aAtkObj);
   NS_ENSURE_TRUE(isMAIObject || MAI_IS_ATK_SOCKET(aAtkObj),
                  nullptr);
 
-  uintptr_t accWrapPtr = isMAIObject ?
-    MAI_ATK_OBJECT(aAtkObj)->accWrap :
-    reinterpret_cast<uintptr_t>(MAI_ATK_SOCKET(aAtkObj)->accWrap);
-  if (accWrapPtr & IS_PROXY)
-    return nullptr;
-
-  AccessibleWrap* accWrap = reinterpret_cast<AccessibleWrap*>(accWrapPtr);
+  AccessibleWrap* accWrap = nullptr;
+  if (isMAIObject) {
+    Accessible* acc = MAI_ATK_OBJECT(aAtkObj)->accWrap.AsAccessible();
+    accWrap = static_cast<AccessibleWrap*>(acc);
+  } else {
+    accWrap = MAI_ATK_SOCKET(aAtkObj)->accWrap;
+  }
 
   // Check if the accessible was deconstructed.
   if (!accWrap)
     return nullptr;
 
   NS_ENSURE_TRUE(accWrap->GetAtkObject() == aAtkObj, nullptr);
 
   AccessibleWrap* appAccWrap = ApplicationAcc();
@@ -1083,22 +1078,26 @@ GetAccessibleWrap(AtkObject* aAtkObj)
     return nullptr;
 
   return accWrap;
 }
 
 ProxyAccessible*
 GetProxy(AtkObject* aObj)
 {
-  if (!aObj || !IS_MAI_OBJECT(aObj) ||
-      !(MAI_ATK_OBJECT(aObj)->accWrap & IS_PROXY))
+  return GetInternalObj(aObj).AsProxy();
+}
+
+AccessibleOrProxy
+GetInternalObj(AtkObject* aObj)
+{
+  if (!aObj || !IS_MAI_OBJECT(aObj))
     return nullptr;
 
-  return reinterpret_cast<ProxyAccessible*>(MAI_ATK_OBJECT(aObj)->accWrap
-      & ~IS_PROXY);
+  return MAI_ATK_OBJECT(aObj)->accWrap;
 }
 
 AtkObject*
 GetWrapperFor(ProxyAccessible* aProxy)
 {
   return reinterpret_cast<AtkObject*>(aProxy->GetWrapper() & ~IS_PROXY);
 }
 
@@ -1660,17 +1659,17 @@ AccessibleWrap::GetColumnHeader(TableAcc
   }
 
   // otherwise get column header for the data cell at the first row.
   TableCellAccessible* tableCell = cell->AsTableCell();
   if (!tableCell) {
     return nullptr;
   }
 
-  nsAutoTArray<Accessible*, 10> headerCells;
+  AutoTArray<Accessible*, 10> headerCells;
   tableCell->ColHeaderCells(&headerCells);
   if (headerCells.IsEmpty()) {
     return nullptr;
   }
 
   return headerCells[0];
 }
 
@@ -1694,16 +1693,16 @@ AccessibleWrap::GetRowHeader(TableAccess
   }
 
   // otherwise get row header for the data cell at the first column.
   TableCellAccessible* tableCell = cell->AsTableCell();
   if (!tableCell) {
     return nullptr;
   }
 
-  nsAutoTArray<Accessible*, 10> headerCells;
+  AutoTArray<Accessible*, 10> headerCells;
   tableCell->RowHeaderCells(&headerCells);
   if (headerCells.IsEmpty()) {
     return nullptr;
   }
 
   return headerCells[0];
 }
--- a/accessible/atk/nsMai.h
+++ b/accessible/atk/nsMai.h
@@ -6,16 +6,17 @@
 
 #ifndef __NS_MAI_H__
 #define __NS_MAI_H__
 
 #include <atk/atk.h>
 #include <glib.h>
 #include <glib-object.h>
 
+#include "AccessibleOrProxy.h"
 #include "AccessibleWrap.h"
 
 namespace mozilla {
 namespace a11y {
 class ProxyAccessible;
 }
 }
 
@@ -61,16 +62,17 @@ typedef struct _MaiAtkSocket
 
 typedef struct _MaiAtkSocketClass
 {
   AtkSocketClass parent_class;
 } MaiAtkSocketClass;
 
 mozilla::a11y::AccessibleWrap* GetAccessibleWrap(AtkObject* aAtkObj);
 mozilla::a11y::ProxyAccessible* GetProxy(AtkObject* aAtkObj);
+mozilla::a11y::AccessibleOrProxy GetInternalObj(AtkObject* aObj);
 AtkObject* GetWrapperFor(mozilla::a11y::ProxyAccessible* aProxy);
 
 extern int atkMajorVersion, atkMinorVersion;
 
 /**
  * Return true if the loaded version of libatk-1.0.so is at least
  * aMajor.aMinor.0.
  */
@@ -90,17 +92,17 @@ static const uintptr_t IS_PROXY = 1;
  */
 struct MaiAtkObject
 {
   AtkObject parent;
   /*
    * The AccessibleWrap whose properties and features are exported
    * via this object instance.
    */
-  uintptr_t accWrap;
+  mozilla::a11y::AccessibleOrProxy accWrap;
 
   /*
    * Get the AtkHyperlink for this atk object.
    */
   AtkHyperlink* GetAtkHyperlink();
 
   /*
    * Shutdown this AtkObject.
--- a/accessible/atk/nsMaiHyperlink.cpp
+++ b/accessible/atk/nsMaiHyperlink.cpp
@@ -95,17 +95,17 @@ mai_atk_hyperlink_get_type(void)
 
         type = g_type_register_static(ATK_TYPE_HYPERLINK,
                                       "MaiAtkHyperlink",
                                       &tinfo, GTypeFlags(0));
     }
     return type;
 }
 
-MaiHyperlink::MaiHyperlink(uintptr_t aHyperLink) :
+MaiHyperlink::MaiHyperlink(AccessibleOrProxy aHyperLink) :
     mHyperlink(aHyperLink),
     mMaiAtkHyperlink(nullptr)
 {
     mMaiAtkHyperlink =
         reinterpret_cast<AtkHyperlink *>
                         (g_object_new(mai_atk_hyperlink_get_type(), nullptr));
     NS_ASSERTION(mMaiAtkHyperlink, "OUT OF MEMORY");
     if (!mMaiAtkHyperlink)
--- a/accessible/atk/nsMaiHyperlink.h
+++ b/accessible/atk/nsMaiHyperlink.h
@@ -18,40 +18,38 @@ namespace a11y {
 
 /*
  * MaiHyperlink is a auxiliary class for MaiInterfaceHyperText.
  */
 
 class MaiHyperlink
 {
 public:
-  explicit MaiHyperlink(uintptr_t aHyperLink);
+  explicit MaiHyperlink(AccessibleOrProxy aHyperLink);
   ~MaiHyperlink();
 
 public:
   AtkHyperlink* GetAtkHyperlink() const { return mMaiAtkHyperlink; }
   Accessible* GetAccHyperlink()
     {
-      if (!mHyperlink || mHyperlink & IS_PROXY)
+      if (!mHyperlink.IsAccessible())
         return nullptr;
 
-      Accessible* link = reinterpret_cast<Accessible*>(mHyperlink);
+      Accessible* link = mHyperlink.AsAccessible();
+      if (!link) {
+        return nullptr;
+      }
+
       NS_ASSERTION(link->IsLink(), "Why isn't it a link!");
       return link;
     }
 
-  ProxyAccessible* Proxy() const
-  {
-    if (!(mHyperlink & IS_PROXY))
-      return nullptr;
-
-    return reinterpret_cast<ProxyAccessible*>(mHyperlink & ~IS_PROXY);
-  }
+  ProxyAccessible* Proxy() const { return mHyperlink.AsProxy(); }
 
 protected:
-  uintptr_t mHyperlink;
+  AccessibleOrProxy mHyperlink;
   AtkHyperlink* mMaiAtkHyperlink;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif /* __MAI_HYPERLINK_H__ */
--- a/accessible/atk/nsMaiInterfaceTable.cpp
+++ b/accessible/atk/nsMaiInterfaceTable.cpp
@@ -268,17 +268,17 @@ getSummaryCB(AtkTable *aTable)
   return nullptr;
 }
 
 static gint
 getSelectedColumnsCB(AtkTable *aTable, gint** aSelected)
 {
   *aSelected = nullptr;
 
-  nsAutoTArray<uint32_t, 10> cols;
+  AutoTArray<uint32_t, 10> cols;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
   if (accWrap) {
     accWrap->AsTable()->SelectedColIndices(&cols);
    } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
     proxy->TableSelectedColumnIndices(&cols);
   } else {
     return 0;
   }
@@ -295,17 +295,17 @@ getSelectedColumnsCB(AtkTable *aTable, g
   memcpy(atkColumns, cols.Elements(), cols.Length() * sizeof(uint32_t));
   *aSelected = atkColumns;
   return cols.Length();
 }
 
 static gint
 getSelectedRowsCB(AtkTable *aTable, gint **aSelected)
 {
-  nsAutoTArray<uint32_t, 10> rows;
+  AutoTArray<uint32_t, 10> rows;
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
   if (accWrap) {
     accWrap->AsTable()->SelectedRowIndices(&rows);
   } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
     proxy->TableSelectedRowIndices(&rows);
   } else {
     return 0;
   }
--- a/accessible/atk/nsMaiInterfaceText.cpp
+++ b/accessible/atk/nsMaiInterfaceText.cpp
@@ -306,17 +306,17 @@ getRunAttributesCB(AtkText *aText, gint 
     return ConvertToAtkTextAttributeSet(attributes);
   }
 
   ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText));
   if (!proxy) {
     return nullptr;
   }
 
-  nsAutoTArray<Attribute, 10> attrs;
+  AutoTArray<Attribute, 10> attrs;
   proxy->TextAttributes(false, aOffset, &attrs, &startOffset, &endOffset);
   *aStartOffset = startOffset;
   *aEndOffset = endOffset;
   return ConvertToAtkTextAttributeSet(attrs);
 }
 
 static AtkAttributeSet*
 getDefaultAttributesCB(AtkText *aText)
@@ -332,17 +332,17 @@ getDefaultAttributesCB(AtkText *aText)
     return ConvertToAtkTextAttributeSet(attributes);
   }
 
   ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText));
   if (!proxy) {
     return nullptr;
   }
 
-  nsAutoTArray<Attribute, 10> attrs;
+  AutoTArray<Attribute, 10> attrs;
   proxy->DefaultTextAttributes(&attrs);
   return ConvertToAtkTextAttributeSet(attrs);
 }
 
 static void
 getCharacterExtentsCB(AtkText *aText, gint aOffset,
                       gint *aX, gint *aY,
                       gint *aWidth, gint *aHeight,
new file mode 100644
--- /dev/null
+++ b/accessible/base/AccessibleOrProxy.h
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_AccessibleOrProxy_h
+#define mozilla_a11y_AccessibleOrProxy_h
+
+#include "mozilla/a11y/Accessible.h"
+#include "mozilla/a11y/ProxyAccessible.h"
+#include "mozilla/a11y/Role.h"
+
+#include <stdint.h>
+
+namespace mozilla {
+namespace a11y {
+
+/**
+ * This class stores an Accessible* or a ProxyAccessible* in a safe manner
+ * with size sizeof(void*).
+ */
+class AccessibleOrProxy
+{
+public:
+  MOZ_IMPLICIT AccessibleOrProxy(Accessible* aAcc) :
+    mBits(reinterpret_cast<uintptr_t>(aAcc)) {}
+  MOZ_IMPLICIT AccessibleOrProxy(ProxyAccessible* aProxy) :
+    mBits(reinterpret_cast<uintptr_t>(aProxy) | IS_PROXY) {}
+  MOZ_IMPLICIT AccessibleOrProxy(decltype(nullptr)) : mBits(0) {}
+
+  bool IsProxy() const { return mBits & IS_PROXY; }
+  ProxyAccessible* AsProxy() const
+  {
+    if (IsProxy()) {
+      return reinterpret_cast<ProxyAccessible*>(mBits & ~IS_PROXY);
+    }
+
+    return nullptr;
+  }
+
+  bool IsAccessible() const { return !IsProxy(); }
+  Accessible* AsAccessible() const
+  {
+    if (IsAccessible()) {
+      return reinterpret_cast<Accessible*>(mBits);
+    }
+
+    return nullptr;
+  }
+
+  bool IsNull() const { return mBits == 0; }
+
+  uint32_t ChildCount() const
+  {
+    if (IsProxy()) {
+      return AsProxy()->ChildrenCount();
+    }
+
+    return AsAccessible()->ChildCount();
+  }
+
+  /**
+   * Return the child object either an accessible or a proxied accessible at
+   * the given index.
+   */
+  AccessibleOrProxy ChildAt(uint32_t aIdx)
+  {
+    if (IsProxy()) {
+      return AsProxy()->ChildAt(aIdx);
+    }
+
+    return AsAccessible()->GetChildAt(aIdx);
+  }
+
+  /**
+   * Return the first child object.
+   */
+  AccessibleOrProxy FirstChild()
+  {
+    if (IsProxy()) {
+      return AsProxy()->FirstChild();
+    }
+
+    return AsAccessible()->FirstChild();
+  }
+
+  /**
+   * Return the first child object.
+   */
+  AccessibleOrProxy LastChild()
+  {
+    if (IsProxy()) {
+      return AsProxy()->LastChild();
+    }
+
+    return AsAccessible()->LastChild();
+  }
+
+  role Role() const
+  {
+    if (IsProxy()) {
+      return AsProxy()->Role();
+    }
+
+    return AsAccessible()->Role();
+  }
+
+  // XXX these are implementation details that ideally would not be exposed.
+  uintptr_t Bits() const { return mBits; }
+  void SetBits(uintptr_t aBits) { mBits = aBits; }
+
+private:
+  uintptr_t mBits;
+  static const uintptr_t IS_PROXY = 0x1;
+};
+
+}
+}
+
+#endif
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -21,30 +21,31 @@
 #endif
 
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
 #include "nsCURILoader.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsIChannel.h"
 #include "nsIDOMDocument.h"
-#include "nsIDOMWindow.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIWebNavigation.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIWebProgress.h"
 #include "nsCoreUtils.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/dom/TabChild.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 using namespace mozilla::dom;
 
 StaticAutoPtr<nsTArray<DocAccessibleParent*>> DocManager::sRemoteDocuments;
+nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>, xpcAccessibleDocument>*
+DocManager::sRemoteXPCDocumentCache = nullptr;
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocManager
 ////////////////////////////////////////////////////////////////////////////////
 
 DocManager::DocManager()
   : mDocAccessibleCache(2), mXPCDocumentCache(0)
 {
@@ -96,30 +97,60 @@ DocManager::NotifyOfDocumentShutdown(Doc
     xpcDoc->Shutdown();
     mXPCDocumentCache.Remove(aDocument);
   }
 
   mDocAccessibleCache.Remove(aDOMDocument);
   RemoveListeners(aDOMDocument);
 }
 
+void
+DocManager::NotifyOfRemoteDocShutdown(DocAccessibleParent* aDoc)
+{
+  xpcAccessibleDocument* doc = GetCachedXPCDocument(aDoc);
+  if (doc) {
+    doc->Shutdown();
+    sRemoteXPCDocumentCache->Remove(aDoc);
+  }
+}
+
 xpcAccessibleDocument*
 DocManager::GetXPCDocument(DocAccessible* aDocument)
 {
   if (!aDocument)
     return nullptr;
 
   xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
   if (!xpcDoc) {
     xpcDoc = new xpcAccessibleDocument(aDocument);
     mXPCDocumentCache.Put(aDocument, xpcDoc);
   }
   return xpcDoc;
 }
 
+xpcAccessibleDocument*
+DocManager::GetXPCDocument(DocAccessibleParent* aDoc)
+{
+  xpcAccessibleDocument* doc = GetCachedXPCDocument(aDoc);
+  if (doc) {
+    return doc;
+  }
+
+  if (!sRemoteXPCDocumentCache) {
+    sRemoteXPCDocumentCache =
+      new nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>, xpcAccessibleDocument>;
+  }
+
+  doc =
+    new xpcAccessibleDocument(aDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT);
+  sRemoteXPCDocumentCache->Put(aDoc, doc);
+
+  return doc;
+}
+
 #ifdef DEBUG
 bool
 DocManager::IsProcessingRefreshDriverNotification() const
 {
   for (auto iter = mDocAccessibleCache.ConstIter(); !iter.Done(); iter.Next()) {
     DocAccessible* docAccessible = iter.UserData();
     NS_ASSERTION(docAccessible,
                  "No doc accessible for the object in doc accessible cache!");
@@ -181,21 +212,21 @@ DocManager::OnStateChange(nsIWebProgress
                           nsresult aStatus)
 {
   NS_ASSERTION(aStateFlags & STATE_IS_DOCUMENT, "Other notifications excluded");
 
   if (nsAccessibilityService::IsShutdown() || !aWebProgress ||
       (aStateFlags & (STATE_START | STATE_STOP)) == 0)
     return NS_OK;
 
-  nsCOMPtr<nsIDOMWindow> DOMWindow;
+  nsCOMPtr<mozIDOMWindowProxy> DOMWindow;
   aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow));
   NS_ENSURE_STATE(DOMWindow);
 
-  nsCOMPtr<nsPIDOMWindow> piWindow = do_QueryInterface(DOMWindow);
+  nsPIDOMWindowOuter* piWindow = nsPIDOMWindowOuter::From(DOMWindow);
   MOZ_ASSERT(piWindow);
 
   nsCOMPtr<nsIDocument> document = piWindow->GetDoc();
   NS_ENSURE_STATE(document);
 
   // Document was loaded.
   if (aStateFlags & STATE_STOP) {
 #ifdef A11Y_LOG
@@ -366,17 +397,17 @@ DocManager::HandleDOMDocumentLoad(nsIDoc
 
   docAcc->NotifyOfLoad(aLoadEventType);
 }
 
 void
 DocManager::AddListeners(nsIDocument* aDocument,
                          bool aAddDOMContentLoadedListener)
 {
-  nsPIDOMWindow* window = aDocument->GetWindow();
+  nsPIDOMWindowOuter* window = aDocument->GetWindow();
   EventTarget* target = window->GetChromeEventHandler();
   EventListenerManager* elm = target->GetOrCreateListenerManager();
   elm->AddEventListenerByType(this, NS_LITERAL_STRING("pagehide"),
                               TrustedEventsAtCapture());
 
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eDocCreate))
     logging::Text("added 'pagehide' listener");
@@ -390,17 +421,17 @@ DocManager::AddListeners(nsIDocument* aD
       logging::Text("added 'DOMContentLoaded' listener");
 #endif
   }
 }
 
 void
 DocManager::RemoveListeners(nsIDocument* aDocument)
 {
-  nsPIDOMWindow* window = aDocument->GetWindow();
+  nsPIDOMWindowOuter* window = aDocument->GetWindow();
   if (!window)
     return;
 
   EventTarget* target = window->GetChromeEventHandler();
   if (!target)
     return;
 
   EventListenerManager* elm = target->GetOrCreateListenerManager();
--- a/accessible/base/DocManager.h
+++ b/accessible/base/DocManager.h
@@ -85,16 +85,31 @@ public:
   /*
    * Notify of a new top level document in a content process.
    */
   static void RemoteDocAdded(DocAccessibleParent* aDoc);
 
   static const nsTArray<DocAccessibleParent*>* TopLevelRemoteDocs()
     { return sRemoteDocuments; }
 
+  /**
+   * Remove the xpc document for a remote document if there is one.
+   */
+  static void NotifyOfRemoteDocShutdown(DocAccessibleParent* adoc);
+
+  /**
+   * Get a XPC document for a remote document.
+   */
+  static xpcAccessibleDocument* GetXPCDocument(DocAccessibleParent* aDoc);
+  static xpcAccessibleDocument* GetCachedXPCDocument(const DocAccessibleParent* aDoc)
+  {
+    return sRemoteXPCDocumentCache ? sRemoteXPCDocumentCache->GetWeak(aDoc)
+      : nullptr;
+  }
+
 #ifdef DEBUG
   bool IsProcessingRefreshDriverNotification() const;
 #endif
 
 protected:
   DocManager();
   virtual ~DocManager() { }
 
@@ -142,16 +157,18 @@ private:
 
   typedef nsRefPtrHashtable<nsPtrHashKey<const nsIDocument>, DocAccessible>
     DocAccessibleHashtable;
   DocAccessibleHashtable mDocAccessibleCache;
 
   typedef nsRefPtrHashtable<nsPtrHashKey<const DocAccessible>, xpcAccessibleDocument>
     XPCDocumentHashtable;
   XPCDocumentHashtable mXPCDocumentCache;
+  static nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>, xpcAccessibleDocument>*
+    sRemoteXPCDocumentCache;
 
   /*
    * The list of remote top level documents.
    */
   static StaticAutoPtr<nsTArray<DocAccessibleParent*>> sRemoteDocuments;
 };
 
 /**
--- a/accessible/base/EventQueue.h
+++ b/accessible/base/EventQueue.h
@@ -71,17 +71,17 @@ private:
 protected:
 
   /**
    * The document accessible reference owning this queue.
    */
   DocAccessible* mDocument;
 
   /**
-   * Pending events array. Don't make this an nsAutoTArray; we use
+   * Pending events array. Don't make this an AutoTArray; we use
    * SwapElements() on it.
    */
   nsTArray<RefPtr<AccEvent> > mEvents;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/base/FocusManager.cpp
+++ b/accessible/base/FocusManager.cpp
@@ -384,17 +384,17 @@ FocusManager::FocusedDOMNode() const
   if (focusedElm) {
     if (EventStateManager::IsRemoteTarget(focusedElm)) {
       return nullptr;
     }
     return focusedElm;
   }
 
   // Otherwise the focus can be on DOM document.
-  nsPIDOMWindow* focusedWnd = DOMFocusManager->GetFocusedWindow();
+  nsPIDOMWindowOuter* focusedWnd = DOMFocusManager->GetFocusedWindow();
   return focusedWnd ? focusedWnd->GetExtantDoc() : nullptr;
 }
 
 nsIDocument*
 FocusManager::FocusedDOMDocument() const
 {
   nsINode* focusedNode = FocusedDOMNode();
   return focusedNode ? focusedNode->OwnerDoc() : nullptr;
--- a/accessible/base/Logging.cpp
+++ b/accessible/base/Logging.cpp
@@ -387,19 +387,19 @@ static const char* sDocEventTitle = "DOC
 static const char* sFocusTitle = "FOCUS";
 
 void
 logging::DocLoad(const char* aMsg, nsIWebProgress* aWebProgress,
                  nsIRequest* aRequest, uint32_t aStateFlags)
 {
   MsgBegin(sDocLoadTitle, aMsg);
 
-  nsCOMPtr<nsIDOMWindow> DOMWindow;
+  nsCOMPtr<mozIDOMWindowProxy> DOMWindow;
   aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow));
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(DOMWindow);
+  nsPIDOMWindowOuter* window = nsPIDOMWindowOuter::From(DOMWindow);
   if (!window) {
     MsgEnd();
     return;
   }
 
   nsCOMPtr<nsIDocument> documentNode = window->GetDoc();
   if (!documentNode) {
     MsgEnd();
--- a/accessible/base/NotificationController.h
+++ b/accessible/base/NotificationController.h
@@ -117,18 +117,25 @@ public:
    */
   void ScheduleChildDocBinding(DocAccessible* aDocument);
 
   /**
    * Schedule the accessible tree update because of rendered text changes.
    */
   inline void ScheduleTextUpdate(nsIContent* aTextNode)
   {
-    if (mTextHash.PutEntry(aTextNode))
-      ScheduleProcessing();
+    // Make sure we are not called with a node that is not in the DOM tree or
+    // not visible.
+    MOZ_ASSERT(aTextNode->GetParentNode(), "A text node is not in DOM");
+    MOZ_ASSERT(aTextNode->GetPrimaryFrame(), "A text node doesn't have a frame");
+    MOZ_ASSERT(aTextNode->GetPrimaryFrame()->StyleVisibility()->IsVisible(),
+               "A text node is not visible");
+
+    mTextHash.PutEntry(aTextNode);
+    ScheduleProcessing();
   }
 
   /**
    * Pend accessible tree update for content insertion.
    */
   void ScheduleContentInsertion(Accessible* aContainer,
                                 nsIContent* aStartChildNode,
                                 nsIContent* aEndChildNode);
@@ -270,17 +277,17 @@ private:
     RefPtr<Accessible> mContainer;
 
     // Array of inserted contents.
     nsTArray<nsCOMPtr<nsIContent> > mInsertedContent;
   };
 
   /**
    * A pending accessible tree update notifications for content insertions.
-   * Don't make this an nsAutoTArray; we use SwapElements() on it.
+   * Don't make this an AutoTArray; we use SwapElements() on it.
    */
   nsTArray<RefPtr<ContentInsertion> > mContentInsertions;
 
   template<class T>
   class nsCOMPtrHashKey : public PLDHashEntryHdr
   {
   public:
     typedef T* KeyType;
@@ -304,17 +311,17 @@ private:
   };
 
   /**
    * A pending accessible tree update notifications for rendered text changes.
    */
   nsTHashtable<nsCOMPtrHashKey<nsIContent> > mTextHash;
 
   /**
-   * Other notifications like DOM events. Don't make this an nsAutoTArray; we
+   * Other notifications like DOM events. Don't make this an AutoTArray; we
    * use SwapElements() on it.
    */
   nsTArray<RefPtr<Notification> > mNotifications;
 
   /**
    * Holds all scheduled relocations.
    */
   nsTArray<RefPtr<Accessible> > mRelocations;
--- a/accessible/base/TextRange-inl.h
+++ b/accessible/base/TextRange-inl.h
@@ -12,17 +12,17 @@
 
 namespace mozilla {
 namespace a11y {
 
 inline Accessible*
 TextRange::Container() const
 {
   uint32_t pos1 = 0, pos2 = 0;
-  nsAutoTArray<Accessible*, 30> parents1, parents2;
+  AutoTArray<Accessible*, 30> parents1, parents2;
   return CommonParent(mStartContainer, mEndContainer,
                       &parents1, &pos1, &parents2, &pos2);
 }
 
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/base/TextRange.cpp
+++ b/accessible/base/TextRange.cpp
@@ -19,17 +19,17 @@ bool
 TextPoint::operator <(const TextPoint& aPoint) const
 {
   if (mContainer == aPoint.mContainer)
     return mOffset < aPoint.mOffset;
 
   // Build the chain of parents
   Accessible* p1 = mContainer;
   Accessible* p2 = aPoint.mContainer;
-  nsAutoTArray<Accessible*, 30> parents1, parents2;
+  AutoTArray<Accessible*, 30> parents1, parents2;
   do {
     parents1.AppendElement(p1);
     p1 = p1->Parent();
   } while (p1);
   do {
     parents2.AppendElement(p2);
     p2 = p2->Parent();
   } while (p2);
@@ -71,17 +71,17 @@ TextRange::EmbeddedChildren(nsTArray<Acc
     }
     return;
   }
 
   Accessible* p1 = mStartContainer->GetChildAtOffset(mStartOffset);
   Accessible* p2 = mEndContainer->GetChildAtOffset(mEndOffset);
 
   uint32_t pos1 = 0, pos2 = 0;
-  nsAutoTArray<Accessible*, 30> parents1, parents2;
+  AutoTArray<Accessible*, 30> parents1, parents2;
   Accessible* container =
     CommonParent(p1, p2, &parents1, &pos1, &parents2, &pos2);
 
   // Traverse the tree up to the container and collect embedded objects.
   for (uint32_t idx = 0; idx < pos1 - 1; idx++) {
     Accessible* parent = parents1[idx + 1];
     Accessible* child = parents1[idx];
     uint32_t childCount = parent->ChildCount();
@@ -141,17 +141,17 @@ TextRange::Normalize(ETextUnit aUnit)
 {
 
 }
 
 bool
 TextRange::Crop(Accessible* aContainer)
 {
   uint32_t boundaryPos = 0, containerPos = 0;
-  nsAutoTArray<Accessible*, 30> boundaryParents, containerParents;
+  AutoTArray<Accessible*, 30> boundaryParents, containerParents;
 
   // Crop the start boundary.
   Accessible* container = nullptr;
   Accessible* boundary = mStartContainer->GetChildAtOffset(mStartOffset);
   if (boundary != aContainer) {
     CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
                  &containerParents, &containerPos);
 
--- a/accessible/base/TreeWalker.h
+++ b/accessible/base/TreeWalker.h
@@ -82,17 +82,17 @@ private:
   /**
    * Pop state from stack.
    */
   ChildrenIterator* PopState();
 
   DocAccessible* mDoc;
   Accessible* mContext;
   nsIContent* mAnchorNode;
-  nsAutoTArray<ChildrenIterator, 20> mStateStack;
+  AutoTArray<ChildrenIterator, 20> mStateStack;
   int32_t mChildFilter;
   uint32_t mFlags;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_TreeWalker_h_
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -11,21 +11,23 @@
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocument.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsRange.h"
 #include "nsIBoxObject.h"
 #include "nsIDOMXULElement.h"
 #include "nsIDocShell.h"
+#include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIScrollableFrame.h"
 #include "nsISelectionPrivate.h"
 #include "nsISelectionController.h"
+#include "nsISimpleEnumerator.h"
 #include "mozilla/dom/TouchEvent.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TouchEvents.h"
 #include "nsView.h"
 #include "nsGkAtoms.h"
 
@@ -653,8 +655,34 @@ nsCoreUtils::IsWhitespaceString(const ns
   aString.BeginReading(iterBegin);
   aString.EndReading(iterEnd);
 
   while (iterBegin != iterEnd && IsWhitespace(*iterBegin))
     ++iterBegin;
 
   return iterBegin == iterEnd;
 }
+
+bool
+nsCoreUtils::AccEventObserversExist()
+{
+  nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
+  NS_ENSURE_TRUE(obsService, false);
+
+  nsCOMPtr<nsISimpleEnumerator> observers;
+  obsService->EnumerateObservers(NS_ACCESSIBLE_EVENT_TOPIC,
+                                 getter_AddRefs(observers));
+  NS_ENSURE_TRUE(observers, false);
+
+  bool hasObservers = false;
+  observers->HasMoreElements(&hasObservers);
+
+  return hasObservers;
+}
+
+void
+nsCoreUtils::DispatchAccEvent(RefPtr<nsIAccessibleEvent> event)
+{
+  nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
+  NS_ENSURE_TRUE_VOID(obsService);
+
+  obsService->NotifyObservers(event, NS_ACCESSIBLE_EVENT_TOPIC, nullptr);
+}
--- a/accessible/base/nsCoreUtils.h
+++ b/accessible/base/nsCoreUtils.h
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsCoreUtils_h_
 #define nsCoreUtils_h_
 
 #include "mozilla/EventForwards.h"
+#include "nsIAccessibleEvent.h"
 #include "nsIContent.h"
 #include "nsIDocument.h" // for GetShell()
 #include "nsIPresShell.h"
 
 #include "nsPoint.h"
 #include "nsTArray.h"
 
 class nsRange;
@@ -314,11 +315,21 @@ public:
   /**
    * Returns true if the given character is whitespace symbol.
    */
   static bool IsWhitespace(char16_t aChar)
   {
     return aChar == ' ' || aChar == '\n' ||
       aChar == '\r' || aChar == '\t' || aChar == 0xa0;
   }
+
+  /*
+   * Return true if there are any observers of accessible events.
+   */
+  static bool AccEventObserversExist();
+
+  /**
+   * Notify accessible event observers of an event.
+   */
+  static void DispatchAccEvent(RefPtr<nsIAccessibleEvent> aEvent);
 };
 
 #endif
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -880,30 +880,18 @@ Accessible::HandleAccEvent(AccEvent* aEv
           break;
                                                      }
         default:
                                                          ipcDoc->SendEvent(id, aEvent->GetEventType());
       }
     }
   }
 
-  nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
-  NS_ENSURE_TRUE(obsService, NS_ERROR_FAILURE);
-
-  nsCOMPtr<nsISimpleEnumerator> observers;
-  obsService->EnumerateObservers(NS_ACCESSIBLE_EVENT_TOPIC,
-                                 getter_AddRefs(observers));
-
-  NS_ENSURE_STATE(observers);
-
-  bool hasObservers = false;
-  observers->HasMoreElements(&hasObservers);
-  if (hasObservers) {
-    nsCOMPtr<nsIAccessibleEvent> event = MakeXPCEvent(aEvent);
-    return obsService->NotifyObservers(event, NS_ACCESSIBLE_EVENT_TOPIC, nullptr);
+  if (nsCoreUtils::AccEventObserversExist()) {
+    nsCoreUtils::DispatchAccEvent(MakeXPCEvent(aEvent));
   }
 
   return NS_OK;
 }
 
 already_AddRefed<nsIPersistentProperties>
 Accessible::Attributes()
 {
--- a/accessible/generic/ApplicationAccessible.cpp
+++ b/accessible/generic/ApplicationAccessible.cpp
@@ -10,17 +10,16 @@
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "Relation.h"
 #include "Role.h"
 #include "States.h"
 
 #include "nsIComponentManager.h"
 #include "nsIDOMDocument.h"
-#include "nsIDOMWindow.h"
 #include "nsIWindowMediator.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/Services.h"
 #include "nsIStringBundle.h"
 
 using namespace mozilla::a11y;
 
 ApplicationAccessible::ApplicationAccessible() :
@@ -188,17 +187,17 @@ ApplicationAccessible::CacheChildren()
   if (NS_FAILED(rv))
     return;
 
   bool hasMore = false;
   windowEnumerator->HasMoreElements(&hasMore);
   while (hasMore) {
     nsCOMPtr<nsISupports> window;
     windowEnumerator->GetNext(getter_AddRefs(window));
-    nsCOMPtr<nsPIDOMWindow> DOMWindow = do_QueryInterface(window);
+    nsCOMPtr<nsPIDOMWindowOuter> DOMWindow = do_QueryInterface(window);
     if (DOMWindow) {
       nsCOMPtr<nsIDocument> docNode = DOMWindow->GetDoc();
       if (docNode) {
         GetAccService()->GetDocAccessible(docNode); // ensure creation
       }
     }
     windowEnumerator->HasMoreElements(&hasMore);
   }
--- a/accessible/generic/HyperTextAccessible.cpp
+++ b/accessible/generic/HyperTextAccessible.cpp
@@ -1355,17 +1355,17 @@ HyperTextAccessible::SetSelectionRange(i
   if (isFocusable)
     return NS_OK;
 
   nsFocusManager* DOMFocusManager = nsFocusManager::GetFocusManager();
   if (DOMFocusManager) {
     NS_ENSURE_TRUE(mDoc, NS_ERROR_FAILURE);
     nsIDocument* docNode = mDoc->DocumentNode();
     NS_ENSURE_TRUE(docNode, NS_ERROR_FAILURE);
-    nsCOMPtr<nsPIDOMWindow> window = docNode->GetWindow();
+    nsCOMPtr<nsPIDOMWindowOuter> window = docNode->GetWindow();
     nsCOMPtr<nsIDOMElement> result;
     DOMFocusManager->MoveFocus(window, nullptr, nsIFocusManager::MOVEFOCUS_CARET,
                                nsIFocusManager::FLAG_BYMOVEFOCUS, getter_AddRefs(result));
   }
 
   return NS_OK;
 }
 
@@ -1461,17 +1461,17 @@ HyperTextAccessible::CaretLineNumber()
     if (hyperTextContent == caretFrame->GetContent()) {
       return lineNumber; // Must be in a single line hyper text, there is no line iterator
     }
     nsContainerFrame *parentFrame = caretFrame->GetParent();
     if (!parentFrame)
       break;
 
     // Add lines for the sibling frames before the caret
-    nsIFrame *sibling = parentFrame->GetFirstPrincipalChild();
+    nsIFrame *sibling = parentFrame->PrincipalChildList().FirstChild();
     while (sibling && sibling != caretFrame) {
       nsAutoLineIterator lineIterForSibling = sibling->GetLineIterator();
       if (lineIterForSibling) {
         // For the frames before that grab all the lines
         int32_t addLines = lineIterForSibling->GetNumLines();
         lineNumber += addLines;
       }
       sibling = sibling->GetNextSibling();
--- a/accessible/generic/ImageAccessible.cpp
+++ b/accessible/generic/ImageAccessible.cpp
@@ -127,21 +127,21 @@ ImageAccessible::DoAction(uint8_t aIndex
   if (!uri)
     return false;
 
   nsAutoCString utf8spec;
   uri->GetSpec(utf8spec);
   NS_ConvertUTF8toUTF16 spec(utf8spec);
 
   nsIDocument* document = mContent->OwnerDoc();
-  nsCOMPtr<nsPIDOMWindow> piWindow = document->GetWindow();
+  nsCOMPtr<nsPIDOMWindowOuter> piWindow = document->GetWindow();
   if (!piWindow)
     return false;
 
-  nsCOMPtr<nsPIDOMWindow> tmp;
+  nsCOMPtr<nsPIDOMWindowOuter> tmp;
   return NS_SUCCEEDED(piWindow->Open(spec, EmptyString(), EmptyString(),
                                      getter_AddRefs(tmp)));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // ImageAccessible
 
 nsIntPoint
--- a/accessible/generic/RootAccessible.cpp
+++ b/accessible/generic/RootAccessible.cpp
@@ -480,22 +480,20 @@ RootAccessible::Shutdown()
 }
 
 Relation
 RootAccessible::RelationByType(RelationType aType)
 {
   if (!mDocumentNode || aType != RelationType::EMBEDS)
     return DocAccessibleWrap::RelationByType(aType);
 
-  nsPIDOMWindow* rootWindow = mDocumentNode->GetWindow();
-  if (rootWindow) {
-    nsCOMPtr<nsIDOMWindow> contentWindow = nsGlobalWindow::Cast(rootWindow)->GetContent();
-    nsCOMPtr<nsPIDOMWindow> piWindow = do_QueryInterface(contentWindow);
-    if (piWindow) {
-      nsCOMPtr<nsIDocument> contentDocumentNode = piWindow->GetDoc();
+  if (nsPIDOMWindowOuter* rootWindow = mDocumentNode->GetWindow()) {
+    nsCOMPtr<nsPIDOMWindowOuter> contentWindow = nsGlobalWindow::Cast(rootWindow)->GetContent();
+    if (contentWindow) {
+      nsCOMPtr<nsIDocument> contentDocumentNode = contentWindow->GetDoc();
       if (contentDocumentNode) {
         DocAccessible* contentDocument =
           GetAccService()->GetDocAccessible(contentDocumentNode);
         if (contentDocument)
           return Relation(contentDocument);
       }
     }
   }
--- a/accessible/interfaces/nsIAccessibleDocument.idl
+++ b/accessible/interfaces/nsIAccessibleDocument.idl
@@ -2,29 +2,29 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIAccessiblePivot;
 interface nsIDOMDocument;
-interface nsIDOMWindow;
+interface mozIDOMWindowProxy;
 
 /**
  * An interface for in-process accessibility clients
  * that wish to retrieve information about a document.
  * When accessibility is turned on in Gecko,
  * there is an nsIAccessibleDocument for each document
  * whether it is XUL, HTML or whatever.
  * You can QueryInterface to nsIAccessibleDocument from the nsIAccessible for
  * the root node of a document or you can get one from
  * nsIAccessible::GetDocument().
  */
-[scriptable, uuid(2be938df-0210-4609-9ece-26b197a517e5)]
+[scriptable, uuid(5cad5f91-fcce-40e7-913e-4671701d19b4)]
 interface nsIAccessibleDocument : nsISupports
 {
   /**
    * The URL of the document
    */
   readonly attribute AString URL;
 
   /**
@@ -45,17 +45,17 @@ interface nsIAccessibleDocument : nsISup
   /**
    * The nsIDOMDocument interface associated with this document.
    */
   readonly attribute nsIDOMDocument DOMDocument;
 
   /**
    * The nsIDOMWindow that the document resides in.
    */
-  readonly attribute nsIDOMWindow window;
+  readonly attribute mozIDOMWindowProxy window;
 
   /**
    * Return the parent document accessible.
    */
   readonly attribute nsIAccessibleDocument parentDocument;
 
   /**
    * Return the count of child document accessibles.
--- a/accessible/interfaces/nsIAccessibleRetrieval.idl
+++ b/accessible/interfaces/nsIAccessibleRetrieval.idl
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIDOMNode;
 interface nsIAccessible;
 interface nsIWeakReference;
 interface nsIPresShell;
-interface nsIDOMWindow;
 interface nsIAccessiblePivot;
 
 /**
  * An interface for in-process accessibility clients wishing to get an
  * nsIAccessible for a given DOM node.  More documentation at:
  *   http://www.mozilla.org/projects/ui/accessibility
  */
 [scriptable, uuid(17f86615-1a3d-4021-b227-3a2ef5cbffd8)]
--- a/accessible/ipc/DocAccessibleChild.cpp
+++ b/accessible/ipc/DocAccessibleChild.cpp
@@ -1043,17 +1043,17 @@ DocAccessibleChild::RecvRowExtent(const 
 }
 
 bool
 DocAccessibleChild::RecvColHeaderCells(const uint64_t& aID,
                                        nsTArray<uint64_t>* aCells)
 {
   TableCellAccessible* acc = IdToTableCellAccessible(aID);
   if (acc) {
-    nsAutoTArray<Accessible*, 10> headerCells;
+    AutoTArray<Accessible*, 10> headerCells;
     acc->ColHeaderCells(&headerCells);
     aCells->SetCapacity(headerCells.Length());
     for (uint32_t i = 0; i < headerCells.Length(); ++i) {
       aCells->AppendElement(
         reinterpret_cast<uint64_t>(headerCells[i]->UniqueID()));
     }
   }
 
@@ -1061,17 +1061,17 @@ DocAccessibleChild::RecvColHeaderCells(c
 }
 
 bool
 DocAccessibleChild::RecvRowHeaderCells(const uint64_t& aID,
                                        nsTArray<uint64_t>* aCells)
 {
   TableCellAccessible* acc = IdToTableCellAccessible(aID);
   if (acc) {
-    nsAutoTArray<Accessible*, 10> headerCells;
+    AutoTArray<Accessible*, 10> headerCells;
     acc->RowHeaderCells(&headerCells);
     aCells->SetCapacity(headerCells.Length());
     for (uint32_t i = 0; i < headerCells.Length(); ++i) {
       aCells->AppendElement(
         reinterpret_cast<uint64_t>(headerCells[i]->UniqueID()));
     }
   }
 
@@ -1363,17 +1363,17 @@ DocAccessibleChild::RecvTableSelectedRow
 }
 
 bool
 DocAccessibleChild::RecvTableSelectedCells(const uint64_t& aID,
                                            nsTArray<uint64_t>* aCellIDs)
 {
   TableAccessible* acc = IdToTableAccessible(aID);
   if (acc) {
-    nsAutoTArray<Accessible*, 30> cells;
+    AutoTArray<Accessible*, 30> cells;
     acc->SelectedCells(&cells);
     aCellIDs->SetCapacity(cells.Length());
     for (uint32_t i = 0; i < cells.Length(); ++i) {
       aCellIDs->AppendElement(
         reinterpret_cast<uint64_t>(cells[i]->UniqueID()));
     }
   }
 
@@ -1524,17 +1524,17 @@ DocAccessibleChild::RecvAtkTableRowHeade
 }
 
 bool
 DocAccessibleChild::RecvSelectedItems(const uint64_t& aID,
                                       nsTArray<uint64_t>* aSelectedItemIDs)
 {
   Accessible* acc = IdToAccessibleSelect(aID);
   if (acc) {
-    nsAutoTArray<Accessible*, 10> selectedItems;
+    AutoTArray<Accessible*, 10> selectedItems;
     acc->SelectedItems(&selectedItems);
     aSelectedItemIDs->SetCapacity(selectedItems.Length());
     for (size_t i = 0; i < selectedItems.Length(); ++i) {
       aSelectedItemIDs->AppendElement(
         reinterpret_cast<uint64_t>(selectedItems[i]->UniqueID()));
     }
   }
 
--- a/accessible/ipc/DocAccessibleParent.cpp
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -4,16 +4,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DocAccessibleParent.h"
 #include "nsAutoPtr.h"
 #include "mozilla/a11y/Platform.h"
 #include "ProxyAccessible.h"
 #include "mozilla/dom/TabParent.h"
+#include "xpcAccessibleDocument.h"
+#include "xpcAccEvents.h"
+#include "nsAccUtils.h"
+#include "nsCoreUtils.h"
 
 namespace mozilla {
 namespace a11y {
 
 bool
 DocAccessibleParent::RecvShowEvent(const ShowEventData& aData)
 {
   if (mShutdown)
@@ -139,44 +143,88 @@ DocAccessibleParent::RecvEvent(const uin
 {
   ProxyAccessible* proxy = GetAccessible(aID);
   if (!proxy) {
     NS_ERROR("no proxy for event!");
     return true;
   }
 
   ProxyEvent(proxy, aEventType);
+
+  if (!nsCoreUtils::AccEventObserversExist()) {
+    return true;
+  }
+
+  xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(proxy);
+  xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
+  nsIDOMNode* node = nullptr;
+  bool fromUser = true; // XXX fix me
+  RefPtr<xpcAccEvent> event = new xpcAccEvent(aEventType, xpcAcc, doc, node,
+                                              fromUser);
+  nsCoreUtils::DispatchAccEvent(Move(event));
+
   return true;
 }
 
 bool
 DocAccessibleParent::RecvStateChangeEvent(const uint64_t& aID,
                                           const uint64_t& aState,
                                           const bool& aEnabled)
 {
   ProxyAccessible* target = GetAccessible(aID);
   if (!target) {
     NS_ERROR("we don't know about the target of a state change event!");
     return true;
   }
 
   ProxyStateChangeEvent(target, aState, aEnabled);
+
+  if (!nsCoreUtils::AccEventObserversExist()) {
+    return true;
+  }
+
+  xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target);
+  xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
+  uint32_t type = nsIAccessibleEvent::EVENT_STATE_CHANGE;
+  bool extra;
+  uint32_t state = nsAccUtils::To32States(aState, &extra);
+  bool fromUser = true; // XXX fix this
+  nsIDOMNode* node = nullptr; // XXX can we do better?
+  RefPtr<xpcAccStateChangeEvent> event =
+    new xpcAccStateChangeEvent(type, xpcAcc, doc, node, fromUser, state, extra,
+                               aEnabled);
+  nsCoreUtils::DispatchAccEvent(Move(event));
+
   return true;
 }
 
 bool
 DocAccessibleParent::RecvCaretMoveEvent(const uint64_t& aID, const int32_t& aOffset)
 {
   ProxyAccessible* proxy = GetAccessible(aID);
   if (!proxy) {
     NS_ERROR("unknown caret move event target!");
     return true;
   }
 
   ProxyCaretMoveEvent(proxy, aOffset);
+
+  if (!nsCoreUtils::AccEventObserversExist()) {
+    return true;
+  }
+
+  xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(proxy);
+  xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
+  nsIDOMNode* node = nullptr;
+  bool fromUser = true; // XXX fix me
+  uint32_t type = nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED;
+  RefPtr<xpcAccCaretMoveEvent> event =
+    new xpcAccCaretMoveEvent(type, xpcAcc, doc, node, fromUser, aOffset);
+  nsCoreUtils::DispatchAccEvent(Move(event));
+
   return true;
 }
 
 bool
 DocAccessibleParent::RecvTextChangeEvent(const uint64_t& aID,
                                          const nsString& aStr,
                                          const int32_t& aStart,
                                          const uint32_t& aLen,
@@ -186,16 +234,29 @@ DocAccessibleParent::RecvTextChangeEvent
   ProxyAccessible* target = GetAccessible(aID);
   if (!target) {
     NS_ERROR("text change event target is unknown!");
     return true;
   }
 
   ProxyTextChangeEvent(target, aStr, aStart, aLen, aIsInsert, aFromUser);
 
+  if (!nsCoreUtils::AccEventObserversExist()) {
+    return true;
+  }
+
+  xpcAccessibleGeneric* xpcAcc = GetXPCAccessible(target);
+  xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
+  uint32_t type = nsIAccessibleEvent::EVENT_TEXT_CHANGED;
+  nsIDOMNode* node = nullptr;
+  RefPtr<xpcAccTextChangeEvent> event =
+    new xpcAccTextChangeEvent(type, xpcAcc, doc, node, aFromUser, aStart, aLen,
+                              aIsInsert, aStr);
+  nsCoreUtils::DispatchAccEvent(Move(event));
+
   return true;
 }
 
 bool
 DocAccessibleParent::RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID)
 {
   // One document should never directly be the child of another.
   // We should always have at least an outer doc accessible in between.
@@ -262,16 +323,18 @@ DocAccessibleParent::Destroy()
   for (uint32_t i = childDocCount - 1; i < childDocCount; i--)
     mChildDocs[i]->Destroy();
 
   for (auto iter = mAccessibles.Iter(); !iter.Done(); iter.Next()) {
     MOZ_ASSERT(iter.Get()->mProxy != this);
     ProxyDestroyed(iter.Get()->mProxy);
     iter.Remove();
   }
+
+  DocManager::NotifyOfRemoteDocShutdown(this);
   ProxyDestroyed(this);
   if (mParentDoc)
     mParentDoc->RemoveChildDoc(this);
   else if (IsTopLevel())
     GetAccService()->RemoteDocShutdown(this);
 }
 
 bool
@@ -285,10 +348,18 @@ DocAccessibleParent::CheckDocTree() cons
     if (!mChildDocs[i]->CheckDocTree()) {
       return false;
     }
   }
 
   return true;
 }
 
+xpcAccessibleGeneric*
+DocAccessibleParent::GetXPCAccessible(ProxyAccessible* aProxy)
+{
+  xpcAccessibleDocument* doc = GetAccService()->GetXPCDocument(this);
+  MOZ_ASSERT(doc);
+
+  return doc->GetXPCAccessible(aProxy);
+}
 } // a11y
 } // mozilla
--- a/accessible/ipc/DocAccessibleParent.h
+++ b/accessible/ipc/DocAccessibleParent.h
@@ -12,16 +12,18 @@
 #include "mozilla/a11y/PDocAccessibleParent.h"
 #include "nsClassHashtable.h"
 #include "nsHashKeys.h"
 #include "nsISupportsImpl.h"
 
 namespace mozilla {
 namespace a11y {
 
+class xpcAccessibleGeneric;
+
 /*
  * These objects live in the main process and comunicate with and represent
  * an accessible document in a content process.
  */
 class DocAccessibleParent : public ProxyAccessible,
     public PDocAccessibleParent
 {
 public:
@@ -154,16 +156,17 @@ private:
 
     ProxyAccessible* mProxy;
   };
 
   uint32_t AddSubtree(ProxyAccessible* aParent,
                       const nsTArray<AccessibleData>& aNewTree, uint32_t aIdx,
                       uint32_t aIdxInParent);
   MOZ_WARN_UNUSED_RESULT bool CheckDocTree() const;
+  xpcAccessibleGeneric* GetXPCAccessible(ProxyAccessible* aProxy);
 
   nsTArray<DocAccessibleParent*> mChildDocs;
   DocAccessibleParent* mParentDoc;
 
   /*
    * Conceptually this is a map from IDs to proxies, but we store the ID in the
    * proxy object so we can't use a real map.
    */
--- a/accessible/ipc/PDocAccessible.ipdl
+++ b/accessible/ipc/PDocAccessible.ipdl
@@ -43,38 +43,38 @@ struct RelationTargets
   uint64_t[] Targets;
 };
 
 prio(normal upto high) sync protocol PDocAccessible
 {
   manager PBrowser;
 
 parent:
-  Shutdown();
+  async Shutdown();
 
   /*
    * Notify the parent process the document in the child process is firing an
    * event.
    */
-  Event(uint64_t aID, uint32_t type);
-  ShowEvent(ShowEventData data);
-  HideEvent(uint64_t aRootID);
-  StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled);
-  CaretMoveEvent(uint64_t aID, int32_t aOffset);
-  TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen,
-                  bool aIsInsert, bool aFromUser);
+  async Event(uint64_t aID, uint32_t type);
+  async ShowEvent(ShowEventData data);
+  async HideEvent(uint64_t aRootID);
+  async StateChangeEvent(uint64_t aID, uint64_t aState, bool aEnabled);
+  async CaretMoveEvent(uint64_t aID, int32_t aOffset);
+  async TextChangeEvent(uint64_t aID, nsString aStr, int32_t aStart, uint32_t aLen,
+                        bool aIsInsert, bool aFromUser);
 
   /*
    * Tell the parent document to bind the existing document as a new child
    * document.
    */
-  BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
+  async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
 
 child:
-  __delete__();
+  async __delete__();
 
   // Accessible
   prio(high) sync State(uint64_t aID) returns(uint64_t states);
   prio(high) sync NativeState(uint64_t aID) returns(uint64_t states);
   prio(high) sync Name(uint64_t aID) returns(nsString name);
   prio(high) sync Value(uint64_t aID) returns(nsString value);
   prio(high) sync Help(uint64_t aID) returns(nsString help);
   prio(high) sync Description(uint64_t aID) returns(nsString desc);
@@ -127,23 +127,23 @@ child:
   prio(high) sync SetSelectionBoundsAt(uint64_t aID, int32_t aSelectionNum,
                                        int32_t aStartOffset, int32_t aEndOffset)
     returns(bool aSucceeded);
   prio(high) sync AddToSelection(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset)
     returns(bool aSucceeded);
   prio(high) sync RemoveFromSelection(uint64_t aID, int32_t aSelectionNum)
     returns(bool aSucceeded);
 
-  ScrollSubstringTo(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset,
-                    uint32_t aScrollType);
-  ScrollSubstringToPoint(uint64_t aID,
-                         int32_t aStartOffset,
-                         int32_t aEndOffset,
-                         uint32_t aCoordinateType,
-                         int32_t aX, int32_t aY);
+  async ScrollSubstringTo(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset,
+                          uint32_t aScrollType);
+  async ScrollSubstringToPoint(uint64_t aID,
+                               int32_t aStartOffset,
+                               int32_t aEndOffset,
+                               uint32_t aCoordinateType,
+                               int32_t aX, int32_t aY);
 
   prio(high) sync Text(uint64_t aID) returns(nsString aText);
   prio(high) sync ReplaceText(uint64_t aID, nsString aText);
   prio(high) sync InsertText(uint64_t aID, nsString aText, int32_t aPosition)
     returns(bool aValid);
   prio(high) sync CopyText(uint64_t aID, int32_t aStartPos, int32_t aEndPos)
     returns(bool aValid);
   prio(high) sync CutText(uint64_t aID, int32_t aStartPos, int32_t aEndPos)
--- a/accessible/ipc/ProxyAccessible.cpp
+++ b/accessible/ipc/ProxyAccessible.cpp
@@ -9,25 +9,31 @@
 #include "DocAccessible.h"
 #include "mozilla/a11y/DocManager.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/unused.h"
 #include "mozilla/a11y/Platform.h"
 #include "RelationType.h"
 #include "mozilla/a11y/Role.h"
+#include "xpcAccessibleDocument.h"
 
 namespace mozilla {
 namespace a11y {
 
 void
 ProxyAccessible::Shutdown()
 {
   MOZ_DIAGNOSTIC_ASSERT(!IsDoc());
   NS_ASSERTION(!mOuterDoc, "Why do we still have a child doc?");
+  xpcAccessibleDocument* xpcDoc =
+    GetAccService()->GetCachedXPCDocument(Document());
+  if (xpcDoc) {
+    xpcDoc->NotifyOfShutdown(this);
+  }
 
   // XXX Ideally  this wouldn't be necessary, but it seems OuterDoc accessibles
   // can be destroyed before the doc they own.
   if (!mOuterDoc) {
     uint32_t childCount = mChildren.Length();
     for (uint32_t idx = 0; idx < childCount; idx++)
       mChildren[idx]->Shutdown();
   } else {
@@ -767,17 +773,17 @@ ProxyAccessible::TableSelectedRowCount()
   uint32_t count = 0;
   Unused << mDoc->SendTableSelectedRowCount(mID, &count);
   return count;
 }
 
 void
 ProxyAccessible::TableSelectedCells(nsTArray<ProxyAccessible*>* aCellIDs)
 {
-  nsAutoTArray<uint64_t, 30> cellIDs;
+  AutoTArray<uint64_t, 30> cellIDs;
   Unused << mDoc->SendTableSelectedCells(mID, &cellIDs);
   aCellIDs->SetCapacity(cellIDs.Length());
   for (uint32_t i = 0; i < cellIDs.Length(); ++i) {
     aCellIDs->AppendElement(mDoc->GetAccessible(cellIDs[i]));
   }
 }
 
 void
@@ -846,17 +852,17 @@ ProxyAccessible::AtkTableRowHeader(int32
   bool ok = false;
   Unused << mDoc->SendAtkTableRowHeader(mID, aRow, &headerID, &ok);
   return ok ? mDoc->GetAccessible(headerID) : nullptr;
 }
 
 void
 ProxyAccessible::SelectedItems(nsTArray<ProxyAccessible*>* aSelectedItems)
 {
-  nsAutoTArray<uint64_t, 10> itemIDs;
+  AutoTArray<uint64_t, 10> itemIDs;
   Unused << mDoc->SendSelectedItems(mID, &itemIDs);
   aSelectedItems->SetCapacity(itemIDs.Length());
   for (size_t i = 0; i < itemIDs.Length(); ++i) {
     aSelectedItems->AppendElement(mDoc->GetAccessible(itemIDs[i]));
   }
 }
 
 uint32_t
--- a/accessible/ipc/moz.build
+++ b/accessible/ipc/moz.build
@@ -19,16 +19,17 @@ if CONFIG['ACCESSIBILITY']:
         'DocAccessibleChild.cpp',
         'DocAccessibleParent.cpp',
         'ProxyAccessible.cpp'
     ]
 
     LOCAL_INCLUDES += [
         '../base',
         '../generic',
+        '../xpcom',
     ]
 
     if CONFIG['MOZ_ENABLE_GTK']:
         LOCAL_INCLUDES += [
             '/accessible/atk',
         ]
     elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
         LOCAL_INCLUDES += [
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -41,17 +41,17 @@ this.AccessFu = { // jshint ignore:line
       if (aWindow.navigator.mozSettings) {
         let lock = aWindow.navigator.mozSettings.createLock();
         let req = lock.get(SCREENREADER_SETTING);
         req.addEventListener('success', () => {
           this._systemPref = req.result[SCREENREADER_SETTING];
           this._enableOrDisable();
         });
         aWindow.navigator.mozSettings.addObserver(
-          SCREENREADER_SETTING, this.handleEvent.bind(this));
+          SCREENREADER_SETTING, this.handleEvent);
       }
     }
 
     this._activatePref = new PrefCache(
       'accessibility.accessfu.activate', this._enableOrDisable.bind(this));
 
     this._enableOrDisable();
   },
@@ -63,23 +63,32 @@ this.AccessFu = { // jshint ignore:line
     // Avoid disabling twice.
     if (this._enabled) {
       this._disable();
     }
     if (Utils.MozBuildApp === 'mobile/android') {
       Services.obs.removeObserver(this, 'Accessibility:Settings');
     } else if (Utils.win.navigator.mozSettings) {
       Utils.win.navigator.mozSettings.removeObserver(
-        SCREENREADER_SETTING, this.handleEvent.bind(this));
+        SCREENREADER_SETTING, this.handleEvent);
     }
     delete this._activatePref;
     Utils.uninit();
   },
 
   /**
+   * A lazy getter for event handler that binds the scope to AccessFu object.
+   */
+  get handleEvent() {
+    delete this.handleEvent;
+    this.handleEvent = this._handleEvent.bind(this);
+    return this.handleEvent;
+  },
+
+  /**
    * Start AccessFu mode, this primarily means controlling the virtual cursor
    * with arrow keys.
    */
   _enable: function _enable() {
     if (this._enabled) {
       return;
     }
     this._enabled = true;
@@ -339,17 +348,17 @@ this.AccessFu = { // jshint ignore:line
           return;
         }
         this._handleMessageManager(frameLoader.messageManager);
         break;
       }
     }
   },
 
-  handleEvent: function handleEvent(aEvent) {
+  _handleEvent: function _handleEvent(aEvent) {
     switch (aEvent.type) {
       case 'TabOpen':
       {
         let mm = Utils.getMessageManager(aEvent.target);
         this._handleMessageManager(mm);
         break;
       }
       case 'TabClose':
--- a/accessible/jsat/Gestures.jsm
+++ b/accessible/jsat/Gestures.jsm
@@ -152,16 +152,24 @@ this.GestureSettings = { // jshint ignor
   /**
    * Maximum consecutive pointer event timeout.
    * @type {Number}
    */
   maxConsecutiveGestureDelay:
     MAX_CONSECUTIVE_GESTURE_DELAY * TIMEOUT_MULTIPLIER,
 
   /**
+   * A maximum time we wait for a next pointer down event to consider a sequence
+   * a multi-action gesture.
+   * @type {Number}
+   */
+  maxGestureResolveTimeout:
+    MAX_CONSECUTIVE_GESTURE_DELAY * TIMEOUT_MULTIPLIER,
+
+  /**
    * Delay before tap turns into dwell
    * @type {Number}
    */
   dwellThreshold: DWELL_THRESHOLD * TIMEOUT_MULTIPLIER,
 
   /**
    * Minimum distance that needs to be travelled for the pointer move to be
    * fired.
@@ -354,17 +362,17 @@ Gesture.prototype = {
    * started the gesture resolution sequence.
    */
   startTimer: function Gesture_startTimer(aTimeStamp) {
     Logger.gesture('startTimer', this.type);
     this.clearTimer();
     let delay = this._getDelay(aTimeStamp);
     let handler = () => {
       Logger.gesture('timer handler');
-      delete this._timer;
+      this.clearTimer();
       if (!this._inProgress) {
         this._deferred.reject();
       } else if (this._rejectToOnWait) {
         this._deferred.reject(this._rejectToOnWait);
       }
     };
     if (delay <= 0) {
       handler();
@@ -497,16 +505,17 @@ Gesture.prototype = {
    * }
    */
   _handleResolve: function Gesture__handleResolve() {
     if (this.isComplete) {
       return;
     }
     Logger.gesture('Resolving', this.id, 'gesture.');
     this.isComplete = true;
+    this.clearTimer();
     let detail = this.compile();
     if (detail) {
       this._emit(detail);
     }
     return {
       id: this.id,
       gestureType: this.resolveTo
     };
@@ -521,16 +530,17 @@ Gesture.prototype = {
    * }
    */
   _handleReject: function Gesture__handleReject(aRejectTo) {
     if (this.isComplete) {
       return;
     }
     Logger.gesture('Rejecting', this.id, 'gesture.');
     this.isComplete = true;
+    this.clearTimer();
     return {
       id: this.id,
       gestureType: aRejectTo
     };
   },
 
   /**
    * A default compilation function used to build the mozAccessFuGesture event
@@ -687,21 +697,22 @@ TapGesture.prototype._getDelay = functio
   return GestureSettings.dwellThreshold;
 };
 
 TapGesture.prototype.pointerup = function TapGesture_pointerup(aPoints) {
     if (this._rejectToOnPointerDown) {
       let complete = this._update(aPoints, 'pointerup', false, true);
       if (complete) {
         this.clearTimer();
-        if (GestureSettings.maxConsecutiveGestureDelay) {
+        if (GestureSettings.maxGestureResolveTimeout) {
           this._pointerUpTimer = setTimeout(() => {
+            clearTimeout(this._pointerUpTimer);
             delete this._pointerUpTimer;
             this._deferred.resolve();
-          }, GestureSettings.maxConsecutiveGestureDelay);
+          }, GestureSettings.maxGestureResolveTimeout);
         } else {
           this._deferred.resolve();
         }
       }
     } else {
       TravelGesture.prototype.pointerup.call(this, aPoints);
     }
 };
--- a/accessible/mac/mozAccessible.mm
+++ b/accessible/mac/mozAccessible.mm
@@ -415,17 +415,17 @@ ConvertToNSArray(nsTArray<ProxyAccessibl
       // Per the MathML 3 spec, the latter happens iff the linethickness
       // attribute is of the form [zero-float][optional-unit]. In that case we
       // set line thickness to zero and in the other cases we set it to one.
       nsAutoString thickness;
       if (accWrap) {
         nsCOMPtr<nsIPersistentProperties> attributes = accWrap->Attributes();
         nsAccUtils::GetAccAttr(attributes, nsGkAtoms::linethickness_, thickness);
       } else {
-        nsAutoTArray<Attribute, 10> attrs;
+        AutoTArray<Attribute, 10> attrs;
         proxy->Attributes(&attrs);
         for (size_t i = 0 ; i < attrs.Length() ; i++) {
           if (attrs.ElementAt(i).Name() == "thickness") {
             thickness = attrs.ElementAt(i).Value();
             break;
           }
         }
       }
@@ -679,21 +679,21 @@ ConvertToNSArray(nsTArray<ProxyAccessibl
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
   AccessibleWrap* accWrap = [self getGeckoAccessible];
   if (mChildren || (accWrap && !accWrap->AreChildrenCached()))
     return mChildren;
 
   // get the array of children.
   if (accWrap) {
-    nsAutoTArray<Accessible*, 10> childrenArray;
+    AutoTArray<Accessible*, 10> childrenArray;
     accWrap->GetUnignoredChildren(&childrenArray);
     mChildren = ConvertToNSArray(childrenArray);
   } else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
-    nsAutoTArray<ProxyAccessible*, 10> childrenArray;
+    AutoTArray<ProxyAccessible*, 10> childrenArray;
     GetProxyUnignoredChildren(proxy, &childrenArray);
     mChildren = ConvertToNSArray(childrenArray);
   }
 
 #ifdef DEBUG_hakan
   // make sure we're not returning any ignored accessibles.
   NSEnumerator *e = [mChildren objectEnumerator];
   mozAccessible *m = nil;
--- a/accessible/mac/mozTableAccessible.mm
+++ b/accessible/mac/mozTableAccessible.mm
@@ -202,22 +202,22 @@
     TableCellAccessible* cell = accWrap->AsTableCell();
     if ([attribute isEqualToString:NSAccessibilityRowIndexRangeAttribute])
       return [NSValue valueWithRange:NSMakeRange(cell->RowIdx(),
                                                  cell->RowExtent())];
     if ([attribute isEqualToString:NSAccessibilityColumnIndexRangeAttribute])
       return [NSValue valueWithRange:NSMakeRange(cell->ColIdx(),
                                                  cell->ColExtent())];
     if ([attribute isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
-      nsAutoTArray<Accessible*, 10> headerCells;
+      AutoTArray<Accessible*, 10> headerCells;
       cell->RowHeaderCells(&headerCells);
       return ConvertToNSArray(headerCells);
     }
     if ([attribute isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute]) {
-      nsAutoTArray<Accessible*, 10> headerCells;
+      AutoTArray<Accessible*, 10> headerCells;
       cell->ColHeaderCells(&headerCells);
       return ConvertToNSArray(headerCells);
     }
   } else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
     if ([attribute isEqualToString:NSAccessibilityRowIndexRangeAttribute])
       return [NSValue valueWithRange:NSMakeRange(proxy->RowIdx(),
                                                  proxy->RowExtent())];
     if ([attribute isEqualToString:NSAccessibilityColumnIndexRangeAttribute])
--- a/accessible/tests/mochitest/elm/test_HTMLSpec.html
+++ b/accessible/tests/mochitest/elm/test_HTMLSpec.html
@@ -369,17 +369,17 @@
           { role: ROLE_TEXT_LEAF } // HTML:del text
         ]
       };
       testElm("del_container", obj);
 
       //////////////////////////////////////////////////////////////////////////
       // HTML:details
 
-      todo(isAccessible("details"), "details element is not accessible");
+      ok(isAccessible("details"), "details element is not accessible");
 
       //////////////////////////////////////////////////////////////////////////
       // HTML:dfn contained by paragraph
 
       obj = {
         role: ROLE_PARAGRAPH,
         textAttrs: {
           0: { "font-style": "italic" },
--- a/accessible/tests/mochitest/jsat/dom_helper.js
+++ b/accessible/tests/mochitest/jsat/dom_helper.js
@@ -2,19 +2,17 @@
 
 /* global getMainChromeWindow, AccessFuTest, GestureSettings, GestureTracker,
    SimpleTest, getBoundsForDOMElm, Point, Utils */
 /* exported loadJSON, eventMap */
 
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 
-Cu.import('resource://gre/modules/accessibility/Utils.jsm');
 Cu.import('resource://gre/modules/Geometry.jsm');
-Cu.import("resource://gre/modules/accessibility/Gestures.jsm");
 
 var win = getMainChromeWindow(window);
 
 /**
  * Convert inch based point coordinates into pixels.
  * @param  {Array} aPoints Array of coordinates in inches.
  * @return {Array} Array of coordinates in pixels.
  */
@@ -95,21 +93,16 @@ sendTouchEvent.touchList = null;
  * @type {Object}
  */
 var eventMap = {
   touchstart: sendTouchEvent,
   touchend: sendTouchEvent,
   touchmove: sendTouchEvent
 };
 
-var originalDwellThreshold = GestureSettings.dwellThreshold;
-var originalSwipeMaxDuration = GestureSettings.swipeMaxDuration;
-var originalConsecutiveGestureDelay =
-  GestureSettings.maxConsecutiveGestureDelay;
-
 /**
  * Attach a listener for the mozAccessFuGesture event that tests its
  * type.
  * @param  {Array} aExpectedGestures A stack of expected event types.
  * @param  {String} aTitle Title of this sequence, if any.
  * Note: the listener is removed once the stack reaches 0.
  */
 function testMozAccessFuGesture(aExpectedGestures, aTitle) {
@@ -153,19 +146,21 @@ function setTimers(aTimeStamp, aRemoveDw
   }
   if (aRemoveSwipeMaxDuration) {
     GestureSettings.swipeMaxDuration = 0;
   }
   GestureTracker.current.clearTimer();
   GestureTracker.current.startTimer(aTimeStamp);
 }
 
-function resetTimers() {
-  GestureSettings.dwellThreshold = originalDwellThreshold;
-  GestureSettings.swipeMaxDuration = originalSwipeMaxDuration;
+function resetTimers(aRemoveGestureResolveDelay) {
+  GestureSettings.dwellThreshold = AccessFuTest.dwellThreshold;
+  GestureSettings.swipeMaxDuration = AccessFuTest.swipeMaxDuration;
+  GestureSettings.maxGestureResolveTimeout = aRemoveGestureResolveDelay ?
+    0 : AccessFuTest.maxGestureResolveTimeout;
 }
 
 /**
  * An extention to AccessFuTest that adds an ability to test a sequence of
  * pointer events and their expected mozAccessFuGesture events.
  * @param {Object} aSequence An object that has a list of pointer events to be
  * generated and the expected mozAccessFuGesture events.
  */
@@ -174,20 +169,17 @@ AccessFuTest.addSequence = function Acce
     testMozAccessFuGesture(aSequence.expectedGestures, aSequence.title);
     var events = aSequence.events;
     function fireEvent(aEvent) {
       var event = {
         points: convertPointCoordinates(aEvent.points),
         type: aEvent.type
       };
       var timeStamp = Date.now();
-      resetTimers();
-      GestureSettings.maxConsecutiveGestureDelay =
-        aEvent.removeConsecutiveGestureDelay ?
-        0 : originalConsecutiveGestureDelay;
+      resetTimers(aEvent.removeGestureResolveDelay);
       GestureTracker.handle(event, timeStamp);
       setTimers(timeStamp, aEvent.removeDwellThreshold,
         aEvent.removeSwipeMaxDuration);
       processEvents();
     }
     function processEvents() {
       if (events.length === 0) {
         return;
--- a/accessible/tests/mochitest/jsat/gestures.json
+++ b/accessible/tests/mochitest/jsat/gestures.json
@@ -1,24 +1,24 @@
 [
   {
     "events": [
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}],
-       "removeConsecutiveGestureDelay": true }
+       "removeGestureResolveDelay": true }
     ],
     "expectedGestures": [{ "type": "tap" }]
   },
   {
     "events": [
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointermove",
         "points": [{"x": 1.03, "y": 1.03, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1.03, "y": 1.03, "identifier": 1}],
-       "removeConsecutiveGestureDelay": true }
+       "removeGestureResolveDelay": true }
     ],
     "expectedGestures": [{ "type": "tap" }]
   },
   {
     "events": [
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}],
         "removeDwellThreshold": true},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]}
@@ -32,29 +32,29 @@
         "points": [{"x": 1.03, "y": 1.02, "identifier": 1}]},
       {"type": "pointerup",
         "points": [{"x": 1.03, "y": 1.02, "identifier": 1}]},
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointermove",
         "points": [{"x": 0.97, "y": 1.01, "identifier": 1}]},
       {"type": "pointerup",
         "points": [{"x": 0.97, "y": 1.01, "identifier": 1}],
-        "removeConsecutiveGestureDelay": true }
+        "removeGestureResolveDelay": true }
     ],
     "expectedGestures": [{ "type": "doubletap" }]
   },
   {
     "events": [
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}],
-       "removeConsecutiveGestureDelay": true }
+       "removeGestureResolveDelay": true }
     ],
     "expectedGestures": [{ "type": "tripletap" }]
   },
   {
     "events": [
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerup", "points": [{"x": 1, "y": 1, "identifier": 1}]},
       {"type": "pointerdown", "points": [{"x": 1, "y": 1, "identifier": 1}]},
@@ -287,17 +287,17 @@
       {"points": [
         {"y": 1.30098, "x": 1.52602, "identifier": 0},
         {"y": 1.94093, "x": 1.02672, "identifier": 1},
         {"y": 2.67229, "x": 0.75246, "identifier": 2}], "type": "pointerdown"},
       {"points": [
         {"y": 1.30098, "x": 1.52602, "identifier": 0},
         {"y": 1.94093, "x": 1.02672, "identifier": 1},
         {"y": 2.67229, "x": 0.75246, "identifier": 2}], "type": "pointerup",
-       "removeConsecutiveGestureDelay": false}],
+       "removeGestureResolveDelay": true}],
     "expectedGestures": [{ "type": "tripletap", "fingers": 3 }]
   },
   {
     "title": "Bug 1182311 - 3 finger triple tap is not reliable 2/2",
     "events": [
       {"type": "pointerdown",
        "points": [{"identifier": 0, "x": 2.21875, "y": 1.510417}]},
       {"type": "pointerdown",
@@ -338,21 +338,15 @@
        "points": [{"identifier": 2, "x": 2.15625, "y": 1.489583}]},
       {"type": "pointermove",
        "points": [{"identifier": 0, "x": 1.4375, "y": 2.59375},
                   {"identifier": 2, "x": 2.15625, "y": 1.489583}]},
       {"type": "pointermove",
        "points": [{"identifier": 0, "x": 1.4375, "y": 2.59375},
                   {"identifier": 2, "x": 2.15625, "y": 1.489583}]},
       {"type": "pointerup",
-       "points": [{"identifier": 1, "x": 1.083333, "y": 3.71875}]},
-      {"type": "pointermove",
-       "points": [{"identifier": 0, "x": 1.427083, "y": 2.59375}]},
-      {"type": "pointerup",
-       "points": [{"identifier": 0, "x": 1.427083, "y": 2.59375}]},
-      {"type": "pointerup",
-       "points": [{"identifier": 2, "x": 2.15625, "y": 1.489583}],
-       "removeConsecutiveGestureDelay": false}
+       "points": [{"identifier": 1, "x": 1.083333, "y": 3.71875}],
+       "removeGestureResolveDelay": true}
     ],
     "expectedGestures": [{ "type": "tripletap", "fingers": 3 }]
   }
 
 ]
--- a/accessible/tests/mochitest/jsat/jsatcommon.js
+++ b/accessible/tests/mochitest/jsat/jsatcommon.js
@@ -14,27 +14,16 @@ var gTestFuncs = [];
   */
 var gIterator;
 
 Components.utils.import('resource://gre/modules/Services.jsm');
 Components.utils.import("resource://gre/modules/accessibility/Utils.jsm");
 Components.utils.import("resource://gre/modules/accessibility/EventManager.jsm");
 Components.utils.import("resource://gre/modules/accessibility/Gestures.jsm");
 
-const dwellThreshold = GestureSettings.dwellThreshold;
-const swipeMaxDuration = GestureSettings.swipeMaxDuration;
-const maxConsecutiveGestureDelay = GestureSettings.maxConsecutiveGestureDelay;
-
-// https://bugzilla.mozilla.org/show_bug.cgi?id=1001945 - sometimes
-// SimpleTest.executeSoon timeout is bigger than the timer settings in
-// GestureSettings that causes intermittents.
-GestureSettings.dwellThreshold = dwellThreshold * 10;
-GestureSettings.swipeMaxDuration = swipeMaxDuration * 10;
-GestureSettings.maxConsecutiveGestureDelay = maxConsecutiveGestureDelay * 10;
-
 var AccessFuTest = {
 
   addFunc: function AccessFuTest_addFunc(aFunc) {
     if (aFunc) {
       gTestFuncs.push(aFunc);
     }
   },
 
@@ -106,19 +95,23 @@ var AccessFuTest = {
     this._waitForExplicitFinish = true;
   },
 
   finish: function AccessFuTest_finish() {
     // Disable the console service logging.
     Logger.test = false;
     Logger.logLevel = Logger.INFO;
     // Reset Gesture Settings.
-    GestureSettings.dwellThreshold = dwellThreshold;
-    GestureSettings.swipeMaxDuration = swipeMaxDuration;
-    GestureSettings.maxConsecutiveGestureDelay = maxConsecutiveGestureDelay;
+    GestureSettings.dwellThreshold = this.dwellThreshold =
+      this.originalDwellThreshold;
+    GestureSettings.swipeMaxDuration = this.swipeMaxDuration =
+      this.originalSwipeMaxDuration;
+    GestureSettings.maxGestureResolveTimeout =
+      this.maxGestureResolveTimeout =
+      this.originalMaxGestureResolveTimeout;
     // Finish through idle callback to let AccessFu._disable complete.
     SimpleTest.executeSoon(function () {
       AccessFu.detach();
       SimpleTest.finish();
     });
   },
 
   nextTest: function AccessFuTest_nextTest() {
@@ -155,16 +148,30 @@ var AccessFuTest = {
       Logger.test = true;
       Logger.logLevel = Logger.DEBUG;
     };
 
     var prefs = [['accessibility.accessfu.notify_output', 1],
       ['dom.mozSettings.enabled', true]];
     prefs.push.apply(prefs, aAdditionalPrefs);
 
+    this.originalDwellThreshold = GestureSettings.dwellThreshold;
+    this.originalSwipeMaxDuration = GestureSettings.swipeMaxDuration;
+    this.originalMaxGestureResolveTimeout =
+      GestureSettings.maxGestureResolveTimeout;
+    // https://bugzilla.mozilla.org/show_bug.cgi?id=1001945 - sometimes
+    // SimpleTest.executeSoon timeout is bigger than the timer settings in
+    // GestureSettings that causes intermittents.
+    this.dwellThreshold = GestureSettings.dwellThreshold =
+      GestureSettings.dwellThreshold * 10;
+    this.swipeMaxDuration = GestureSettings.swipeMaxDuration =
+      GestureSettings.swipeMaxDuration * 10;
+    this.maxGestureResolveTimeout = GestureSettings.maxGestureResolveTimeout =
+      GestureSettings.maxGestureResolveTimeout * 10;
+
     SpecialPowers.pushPrefEnv({ 'set': prefs }, function () {
       if (AccessFuTest._waitForExplicitFinish) {
         // Run all test functions asynchronously.
         AccessFuTest.nextTest();
       } else {
         // Run all test functions synchronously.
         gTestFuncs.forEach(testFunc => testFunc());
         AccessFuTest.finish();
--- a/accessible/tests/mochitest/jsat/test_live_regions.html
+++ b/accessible/tests/mochitest/jsat/test_live_regions.html
@@ -15,17 +15,17 @@
 
     function startAccessFu() {
       SpecialPowers.setIntPref("accessibility.accessfu.activate", 1);
       AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest);
     }
 
     function stopAccessFu() {
       SpecialPowers.setIntPref("accessibility.accessfu.activate", 0);
-      AccessFuTest.once_log("EventManager.stop", AccessFuTest.finish);
+      AccessFuTest.once_log("EventManager.stop", () => AccessFuTest.finish());
     }
 
     function hide(id) {
       var element = document.getElementById(id);
       element.style.display = "none";
     }
 
     function show(id) {
--- a/accessible/tests/mochitest/jsat/test_quicknav_modes.html
+++ b/accessible/tests/mochitest/jsat/test_quicknav_modes.html
@@ -63,17 +63,17 @@
           aCallback();
         });
       }
     }
 
     // Listen for initial 'EventManager.start' and disable AccessFu.
     function prefStop() {
       ok(AccessFu._enabled, "AccessFu was started via preference.");
-      AccessFuTest.once_log("EventManager.stop", AccessFuTest.finish);
+      AccessFuTest.once_log("EventManager.stop", () => AccessFuTest.finish());
       SpecialPowers.setIntPref("accessibility.accessfu.activate", 0);
     }
 
     function doTest() {
       AccessFuTest.addFunc(prefStart);
       AccessFuTest.addFunc(nextMode('Link', 'Heading'));
       AccessFuTest.addFunc(nextMode('Heading', 'FormElement'));
       AccessFuTest.addFunc(nextMode('FormElement', 'Link'));
--- a/accessible/tests/mochitest/table/test_indexes_table.html
+++ b/accessible/tests/mochitest/table/test_indexes_table.html
@@ -105,17 +105,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       testTableIndexes("tableinsane4", idxes);
 
       //////////////////////////////////////////////////////////////////////////
       // tableinsane5 (just a crazy table)
       idxes = [
         [ 0,  1,  2, -1, -1],
         [-1, -1, -1, -1, -1],
         [ 3,  4,  5, -1, -1],
-        [ 6,  7,  7,  7,  7],
+        [ 6,  7,  -1,  -1,  -1],
         [ 6,  8,  9, -1, -1],
         [ 6, 10,  9, 11, 12]
       ];
       testTableIndexes("tableinsane5", idxes);
 
       //////////////////////////////////////////////////////////////////////////
       // tableinsane6 (overlapping cells, mad table)
       idxes = [
--- a/accessible/windows/ia2/ia2Accessible.cpp
+++ b/accessible/windows/ia2/ia2Accessible.cpp
@@ -763,17 +763,17 @@ ia2Accessible::get_selectionRanges(IA2Ra
     return E_INVALIDARG;
 
   *aNRanges = 0;
 
   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   if (acc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
-  nsAutoTArray<TextRange, 1> ranges;
+  AutoTArray<TextRange, 1> ranges;
   acc->Document()->SelectionRanges(&ranges);
   uint32_t len = ranges.Length();
   for (uint32_t idx = 0; idx < len; idx++) {
     if (!ranges[idx].Crop(acc)) {
       ranges.RemoveElementAt(idx);
     }
   }
 
--- a/accessible/windows/ia2/ia2AccessibleTable.cpp
+++ b/accessible/windows/ia2/ia2AccessibleTable.cpp
@@ -366,17 +366,17 @@ ia2AccessibleTable::get_selectedChildren
   if (!aChildren || !aNChildren)
     return E_INVALIDARG;
 
   *aChildren = nullptr;
   *aNChildren = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
-  nsAutoTArray<uint32_t, 30> cellIndices;
+  AutoTArray<uint32_t, 30> cellIndices;
   mTable->SelectedCellIndices(&cellIndices);
 
   uint32_t maxCells = cellIndices.Length();
   if (maxCells == 0)
     return S_FALSE;
 
   *aChildren = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxCells));
   *aNChildren = maxCells;
@@ -658,17 +658,17 @@ ia2AccessibleTable::get_selectedCells(IU
   if (!aCells || !aNSelectedCells)
     return E_INVALIDARG;
 
   *aCells = nullptr;
   *aNSelectedCells = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
-  nsAutoTArray<Accessible*, 30> cells;
+  AutoTArray<Accessible*, 30> cells;
   mTable->SelectedCells(&cells);
   if (cells.IsEmpty())
     return S_FALSE;
 
   *aCells =
     static_cast<IUnknown**>(::CoTaskMemAlloc(sizeof(IUnknown*) *
                                              cells.Length()));
   if (!*aCells)
@@ -694,17 +694,17 @@ ia2AccessibleTable::get_selectedColumns(
   if (!aColumns || !aNColumns)
     return E_INVALIDARG;
 
   *aColumns = nullptr;
   *aNColumns = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
-  nsAutoTArray<uint32_t, 30> colIndices;
+  AutoTArray<uint32_t, 30> colIndices;
   mTable->SelectedColIndices(&colIndices);
 
   uint32_t maxCols = colIndices.Length();
   if (maxCols == 0)
     return S_FALSE;
 
   *aColumns = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxCols));
   *aNColumns = maxCols;
@@ -724,17 +724,17 @@ ia2AccessibleTable::get_selectedRows(lon
   if (!aRows || !aNRows)
     return E_INVALIDARG;
 
   *aRows = nullptr;
   *aNRows = 0;
   if (!mTable)
     return CO_E_OBJNOTCONNECTED;
 
-  nsAutoTArray<uint32_t, 30> rowIndices;
+  AutoTArray<uint32_t, 30> rowIndices;
   mTable->SelectedRowIndices(&rowIndices);
 
   uint32_t maxRows = rowIndices.Length();
   if (maxRows == 0)
     return S_FALSE;
 
   *aRows = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxRows));
   *aNRows = maxRows;
--- a/accessible/windows/ia2/ia2AccessibleTableCell.cpp
+++ b/accessible/windows/ia2/ia2AccessibleTableCell.cpp
@@ -95,17 +95,17 @@ ia2AccessibleTableCell::get_columnHeader
   if (!aCellAccessibles || !aNColumnHeaderCells)
     return E_INVALIDARG;
 
   *aCellAccessibles = nullptr;
   *aNColumnHeaderCells = 0;
   if (!mTableCell)
     return CO_E_OBJNOTCONNECTED;
 
-  nsAutoTArray<Accessible*, 10> cells;
+  AutoTArray<Accessible*, 10> cells;
   mTableCell->ColHeaderCells(&cells);
 
   *aNColumnHeaderCells = cells.Length();
   *aCellAccessibles =
     static_cast<IUnknown**>(::CoTaskMemAlloc(sizeof(IUnknown*) *
                                              cells.Length()));
 
   if (!*aCellAccessibles)
@@ -167,17 +167,17 @@ ia2AccessibleTableCell::get_rowHeaderCel
   if (!aCellAccessibles || !aNRowHeaderCells)
     return E_INVALIDARG;
 
   *aCellAccessibles = nullptr;
   *aNRowHeaderCells = 0;
   if (!mTableCell)
     return CO_E_OBJNOTCONNECTED;
 
-  nsAutoTArray<Accessible*, 10> cells;
+  AutoTArray<Accessible*, 10> cells;
   mTableCell->RowHeaderCells(&cells);
 
   *aNRowHeaderCells = cells.Length();
   *aCellAccessibles =
     static_cast<IUnknown**>(::CoTaskMemAlloc(sizeof(IUnknown*) *
                                              cells.Length()));
   if (!*aCellAccessibles)
     return E_OUTOFMEMORY;
--- a/accessible/windows/ia2/ia2AccessibleText.cpp
+++ b/accessible/windows/ia2/ia2AccessibleText.cpp
@@ -56,17 +56,17 @@ ia2AccessibleText::get_attributes(long a
 
   *aStartOffset = 0;
   *aEndOffset = 0;
   *aTextAttributes = nullptr;
 
   int32_t startOffset = 0, endOffset = 0;
   HRESULT hr;
   if (ProxyAccessible* proxy = HyperTextProxyFor(this)) {
-    nsAutoTArray<Attribute, 10> attrs;
+    AutoTArray<Attribute, 10> attrs;
     proxy->TextAttributes(true, aOffset, &attrs, &startOffset, &endOffset);
     hr = AccessibleWrap::ConvertToIA2Attributes(&attrs, aTextAttributes);
   } else {
     HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this);
     if (textAcc->IsDefunct())
       return CO_E_OBJNOTCONNECTED;
 
     nsCOMPtr<nsIPersistentProperties> attributes =
--- a/accessible/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/windows/msaa/AccessibleWrap.cpp
@@ -829,17 +829,17 @@ AccessibleWrap::get_accSelection(VARIANT
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   // TODO make this work with proxies.
   if (IsProxy())
     return E_NOTIMPL;
 
   if (IsSelect()) {
-    nsAutoTArray<Accessible*, 10> selectedItems;
+    AutoTArray<Accessible*, 10> selectedItems;
     if (IsProxy()) {
       nsTArray<ProxyAccessible*> proxies;
       Proxy()->SelectedItems(&proxies);
 
       uint32_t selectedCount = proxies.Length();
       for (uint32_t i = 0; i < selectedCount; i++) {
         selectedItems.AppendElement(WrapperFor(proxies[i]));
       }
--- a/accessible/windows/msaa/nsWinUtils.cpp
+++ b/accessible/windows/msaa/nsWinUtils.cpp
@@ -40,18 +40,17 @@ nsRefPtrHashtable<nsPtrHashKey<void>, Do
 already_AddRefed<nsIDOMCSSStyleDeclaration>
 nsWinUtils::GetComputedStyleDeclaration(nsIContent* aContent)
 {
   nsIContent* elm = nsCoreUtils::GetDOMElementFor(aContent);
   if (!elm)
     return nullptr;
 
   // Returns number of items in style declaration
-  nsCOMPtr<nsPIDOMWindow> window =
-    do_QueryInterface(elm->OwnerDoc()->GetInnerWindow());
+  nsCOMPtr<nsPIDOMWindowInner> window = elm->OwnerDoc()->GetInnerWindow();
   if (!window)
     return nullptr;
 
   ErrorResult dummy;
   nsCOMPtr<nsICSSDeclaration> cssDecl;
   nsCOMPtr<Element> domElement(do_QueryInterface(elm));
   cssDecl = window->GetComputedStyle(*domElement, EmptyString(), dummy);
   nsCOMPtr<nsIDOMCSSStyleDeclaration> domDecl = do_QueryInterface(cssDecl);
--- a/accessible/xpcom/moz.build
+++ b/accessible/xpcom/moz.build
@@ -59,8 +59,10 @@ xpc_acc_events_h = GENERATED_FILES['xpcA
 xpc_acc_events_h.script = 'AccEventGen.py:gen_header_file'
 xpc_acc_events_h.inputs += ['AccEvents.conf']
 
 xpc_acc_events_cpp = GENERATED_FILES['xpcAccEvents.cpp']
 xpc_acc_events_cpp.script = 'AccEventGen.py:gen_cpp_file'
 xpc_acc_events_cpp.inputs += ['AccEvents.conf']
 
 FINAL_LIBRARY = 'xul'
+
+include('/ipc/chromium/chromium-config.mozbuild')
--- a/accessible/xpcom/xpcAccessible.cpp
+++ b/accessible/xpcom/xpcAccessible.cpp
@@ -60,91 +60,91 @@ xpcAccessible::GetPreviousSibling(nsIAcc
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetFirstChild(nsIAccessible** aFirstChild)
 {
   NS_ENSURE_ARG_POINTER(aFirstChild);
   *aFirstChild = nullptr;
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
-  NS_IF_ADDREF(*aFirstChild = ToXPC(Intl()->FirstChild()));
+  NS_IF_ADDREF(*aFirstChild = ToXPC(IntlGeneric().FirstChild()));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetLastChild(nsIAccessible** aLastChild)
 {
   NS_ENSURE_ARG_POINTER(aLastChild);
   *aLastChild = nullptr;
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
-  NS_IF_ADDREF(*aLastChild = ToXPC(Intl()->LastChild()));
+  NS_IF_ADDREF(*aLastChild = ToXPC(IntlGeneric().LastChild()));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetChildCount(int32_t* aChildCount)
 {
   NS_ENSURE_ARG_POINTER(aChildCount);
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
-  *aChildCount = Intl()->ChildCount();
+  *aChildCount = IntlGeneric().ChildCount();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetChildAt(int32_t aChildIndex, nsIAccessible** aChild)
 {
   NS_ENSURE_ARG_POINTER(aChild);
   *aChild = nullptr;
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
   // If child index is negative, then return last child.
   // XXX: do we really need this?
   if (aChildIndex < 0)
-    aChildIndex = Intl()->ChildCount() - 1;
+    aChildIndex = IntlGeneric().ChildCount() - 1;
 
-  Accessible* child = Intl()->GetChildAt(aChildIndex);
-  if (!child)
+  AccessibleOrProxy child = IntlGeneric().ChildAt(aChildIndex);
+  if (child.IsNull())
     return NS_ERROR_INVALID_ARG;
 
   NS_ADDREF(*aChild = ToXPC(child));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetChildren(nsIArray** aChildren)
 {
   NS_ENSURE_ARG_POINTER(aChildren);
   *aChildren = nullptr;
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsIMutableArray> children =
     do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  uint32_t childCount = Intl()->ChildCount();
+  uint32_t childCount = IntlGeneric().ChildCount();
   for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
-    Accessible* child = Intl()->GetChildAt(childIdx);
+    AccessibleOrProxy child = IntlGeneric().ChildAt(childIdx);
     children->AppendElement(static_cast<nsIAccessible*>(ToXPC(child)), false);
   }
 
-  NS_ADDREF(*aChildren = children);
+  children.forget(aChildren);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetIndexInParent(int32_t* aIndexInParent)
 {
   NS_ENSURE_ARG_POINTER(aIndexInParent);
   *aIndexInParent = -1;
@@ -199,20 +199,20 @@ xpcAccessible::GetRootDocument(nsIAccess
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetRole(uint32_t* aRole)
 {
   NS_ENSURE_ARG_POINTER(aRole);
   *aRole = nsIAccessibleRole::ROLE_NOTHING;
 
-  if (!Intl())
+  if (IntlGeneric().IsNull())
     return NS_ERROR_FAILURE;
 
-  *aRole = Intl()->Role();
+  *aRole = IntlGeneric().Role();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessible::GetState(uint32_t* aState, uint32_t* aExtraState)
 {
   NS_ENSURE_ARG_POINTER(aState);
 
--- a/accessible/xpcom/xpcAccessible.h
+++ b/accessible/xpcom/xpcAccessible.h
@@ -10,16 +10,17 @@
 #include "nsIAccessible.h"
 
 class nsIAccessible;
 
 namespace mozilla {
 namespace a11y {
 
 class Accessible;
+class AccessibleOrProxy;
 
 /**
  * XPCOM nsIAccessible interface implementation, used by xpcAccessibleGeneric
  * class.
  */
 class xpcAccessible : public nsIAccessible
 {
 public:
@@ -87,16 +88,17 @@ public:
                            int32_t aX, int32_t aY) final override;
 
 protected:
   xpcAccessible() { }
   virtual ~xpcAccessible() {}
 
 private:
   Accessible* Intl();
+  AccessibleOrProxy IntlGeneric();
 
   xpcAccessible(const xpcAccessible&) = delete;
   xpcAccessible& operator =(const xpcAccessible&) = delete;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/xpcom/xpcAccessibleApplication.h
+++ b/accessible/xpcom/xpcAccessibleApplication.h
@@ -31,17 +31,17 @@ public:
   NS_IMETHOD GetAppVersion(nsAString& aVersion) final override;
   NS_IMETHOD GetPlatformName(nsAString& aName) final override;
   NS_IMETHOD GetPlatformVersion(nsAString& aVersion) final override;
 
 protected:
   virtual ~xpcAccessibleApplication() {}
 
 private:
-  ApplicationAccessible* Intl() { return mIntl->AsApplication(); }
+  ApplicationAccessible* Intl() { return mIntl.AsAccessible()->AsApplication(); }
 
   xpcAccessibleApplication(const xpcAccessibleApplication&) = delete;
   xpcAccessibleApplication& operator =(const xpcAccessibleApplication&) = delete;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/xpcom/xpcAccessibleDocument.cpp
+++ b/accessible/xpcom/xpcAccessibleDocument.cpp
@@ -4,19 +4,21 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "xpcAccessibleDocument.h"
 #include "xpcAccessibleImage.h"
 #include "xpcAccessibleTable.h"
 #include "xpcAccessibleTableCell.h"
 
+#include "mozilla/a11y/DocAccessibleParent.h"
 #include "DocAccessible-inl.h"
 #include "nsIDOMDocument.h"
 
+using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsISupports and cycle collection
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(xpcAccessibleDocument)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(xpcAccessibleDocument,
@@ -92,17 +94,17 @@ xpcAccessibleDocument::GetDOMDocument(ns
 
   if (Intl()->DocumentNode())
     CallQueryInterface(Intl()->DocumentNode(), aDOMDocument);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-xpcAccessibleDocument::GetWindow(nsIDOMWindow** aDOMWindow)
+xpcAccessibleDocument::GetWindow(mozIDOMWindowProxy** aDOMWindow)
 {
   NS_ENSURE_ARG_POINTER(aDOMWindow);
   *aDOMWindow = nullptr;
 
   if (!Intl())
     return NS_ERROR_FAILURE;
 
   NS_IF_ADDREF(*aDOMWindow = Intl()->DocumentNode()->GetWindow());
@@ -163,16 +165,17 @@ xpcAccessibleDocument::GetVirtualCursor(
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // xpcAccessibleDocument
 
 xpcAccessibleGeneric*
 xpcAccessibleDocument::GetAccessible(Accessible* aAccessible)
 {
+  MOZ_ASSERT(!mRemote);
   if (ToXPCDocument(aAccessible->Document()) != this) {
     NS_ERROR("This XPCOM document is not related with given internal accessible!");
     return nullptr;
   }
 
   if (aAccessible->IsDoc())
     return this;
 
@@ -190,17 +193,53 @@ xpcAccessibleDocument::GetAccessible(Acc
     xpcAcc = new xpcAccessibleHyperText(aAccessible);
   else
     xpcAcc = new xpcAccessibleGeneric(aAccessible);
 
   mCache.Put(aAccessible, xpcAcc);
   return xpcAcc;
 }
 
+xpcAccessibleGeneric*
+xpcAccessibleDocument::GetXPCAccessible(ProxyAccessible* aProxy)
+{
+  MOZ_ASSERT(mRemote);
+  MOZ_ASSERT(aProxy->Document() == mIntl.AsProxy());
+  if (aProxy->IsDoc()) {
+    return this;
+  }
+
+  xpcAccessibleGeneric* acc = mCache.GetWeak(aProxy);
+  if (acc) {
+    return acc;
+  }
+
+  // XXX support exposing optional interfaces.
+  acc = new xpcAccessibleGeneric(aProxy, 0);
+  mCache.Put(aProxy, acc);
+
+  return acc;
+}
+
 void
 xpcAccessibleDocument::Shutdown()
 {
   for (auto iter = mCache.Iter(); !iter.Done(); iter.Next()) {
     iter.Data()->Shutdown();
     iter.Remove();
   }
   xpcAccessibleGeneric::Shutdown();
 }
+
+xpcAccessibleGeneric*
+a11y::ToXPC(AccessibleOrProxy aAcc)
+{
+  if (aAcc.IsNull()) {
+    return nullptr;
+  }
+
+  if (aAcc.IsAccessible()) {
+    return ToXPC(aAcc.AsAccessible());
+  }
+
+ xpcAccessibleDocument* doc = ToXPCDocument(aAcc.AsProxy()->Document());
+ return doc->GetXPCAccessible(aAcc.AsProxy());
+}
--- a/accessible/xpcom/xpcAccessibleDocument.h
+++ b/accessible/xpcom/xpcAccessibleDocument.h
@@ -20,83 +20,111 @@ namespace a11y {
 /**
  * XPCOM wrapper around DocAccessible class.
  */
 class xpcAccessibleDocument : public xpcAccessibleHyperText,
                               public nsIAccessibleDocument
 {
 public:
   explicit xpcAccessibleDocument(DocAccessible* aIntl) :
-    xpcAccessibleHyperText(aIntl), mCache(kDefaultCacheLength) { }
+    xpcAccessibleHyperText(aIntl), mCache(kDefaultCacheLength), mRemote(false) { }
+
+  xpcAccessibleDocument(ProxyAccessible* aProxy, uint32_t aInterfaces) :
+    xpcAccessibleHyperText(aProxy, aInterfaces), mCache(kDefaultCacheLength),
+    mRemote(true) {}
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(xpcAccessibleDocument,
                                            xpcAccessibleGeneric)
 
   // nsIAccessibleDocument
   NS_IMETHOD GetURL(nsAString& aURL) final override;
   NS_IMETHOD GetTitle(nsAString& aTitle) final override;
   NS_IMETHOD GetMimeType(nsAString& aType) final override;
   NS_IMETHOD GetDocType(nsAString& aType) final override;
   NS_IMETHOD GetDOMDocument(nsIDOMDocument** aDOMDocument) final override;
-  NS_IMETHOD GetWindow(nsIDOMWindow** aDOMWindow) final override;
+  NS_IMETHOD GetWindow(mozIDOMWindowProxy** aDOMWindow) final override;
   NS_IMETHOD GetParentDocument(nsIAccessibleDocument** aDocument)
     final override;
   NS_IMETHOD GetChildDocumentCount(uint32_t* aCount) final override;
   NS_IMETHOD GetChildDocumentAt(uint32_t aIndex,
                                 nsIAccessibleDocument** aDocument)
     final override;
   NS_IMETHOD GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor)
     final override;
 
   /**
    * Return XPCOM wrapper for the internal accessible.
    */
   xpcAccessibleGeneric* GetAccessible(Accessible* aAccessible);
+  xpcAccessibleGeneric* GetXPCAccessible(ProxyAccessible* aProxy);
 
   virtual void Shutdown() override;
 
 protected:
   virtual ~xpcAccessibleDocument() {}
 
 private:
-  DocAccessible* Intl() { return mIntl->AsDoc(); }
+  DocAccessible* Intl()
+  {
+    if (Accessible* acc = mIntl.AsAccessible()) {
+      return acc->AsDoc();
+    }
+
+    return nullptr;
+  }
 
   void NotifyOfShutdown(Accessible* aAccessible)
   {
+    MOZ_ASSERT(!mRemote);
     xpcAccessibleGeneric* xpcAcc = mCache.GetWeak(aAccessible);
     if (xpcAcc)
       xpcAcc->Shutdown();
 
     mCache.Remove(aAccessible);
   }
 
+  void NotifyOfShutdown(ProxyAccessible* aProxy)
+  {
+    MOZ_ASSERT(mRemote);
+    xpcAccessibleGeneric* acc = mCache.GetWeak(aProxy);
+    if (acc) {
+      acc->Shutdown();
+    }
+
+    mCache.Remove(aProxy);
+  }
+
   friend class DocManager;
   friend class DocAccessible;
+  friend class ProxyAccessible;
 
   xpcAccessibleDocument(const xpcAccessibleDocument&) = delete;
   xpcAccessibleDocument& operator =(const xpcAccessibleDocument&) = delete;
 
-  nsRefPtrHashtable<nsPtrHashKey<const Accessible>, xpcAccessibleGeneric> mCache;
+  nsRefPtrHashtable<nsPtrHashKey<const void>, xpcAccessibleGeneric> mCache;
+  bool mRemote;
 };
 
 inline xpcAccessibleGeneric*
 ToXPC(Accessible* aAccessible)
 {
   if (!aAccessible)
     return nullptr;
 
   if (aAccessible->IsApplication())
     return XPCApplicationAcc();
 
   xpcAccessibleDocument* xpcDoc =
     GetAccService()->GetXPCDocument(aAccessible->Document());
   return xpcDoc ? xpcDoc->GetAccessible(aAccessible) : nullptr;
 }
 
+xpcAccessibleGeneric* ToXPC(AccessibleOrProxy aAcc);
+
 inline xpcAccessibleHyperText*
 ToXPCText(HyperTextAccessible* aAccessible)
 {
   if (!aAccessible)
     return nullptr;
 
   xpcAccessibleDocument* xpcDoc =
     GetAccService()->GetXPCDocument(aAccessible->Document());
@@ -104,12 +132,18 @@ ToXPCText(HyperTextAccessible* aAccessib
 }
 
 inline xpcAccessibleDocument*
 ToXPCDocument(DocAccessible* aAccessible)
 {
   return GetAccService()->GetXPCDocument(aAccessible);
 }
 
+inline xpcAccessibleDocument*
+ToXPCDocument(DocAccessibleParent* aAccessible)
+{
+  return GetAccService()->GetXPCDocument(aAccessible);
+}
+
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/xpcom/xpcAccessibleGeneric.cpp
+++ b/accessible/xpcom/xpcAccessibleGeneric.cpp
@@ -28,17 +28,17 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(xpcAcces
 NS_IMPL_CYCLE_COLLECTING_RELEASE(xpcAccessibleGeneric)
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIAccessible
 
 Accessible*
 xpcAccessibleGeneric::ToInternalAccessible() const
 {
-  return mIntl;
+  return mIntl.AsAccessible();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // xpcAccessibleGeneric
 
 void
 xpcAccessibleGeneric::Shutdown()
 {
--- a/accessible/xpcom/xpcAccessibleGeneric.h
+++ b/accessible/xpcom/xpcAccessibleGeneric.h
@@ -8,53 +8,68 @@
 #define mozilla_a11y_xpcAccessibleGeneric_h_
 
 #include "xpcAccessible.h"
 #include "xpcAccessibleHyperLink.h"
 #include "xpcAccessibleSelectable.h"
 #include "xpcAccessibleValue.h"
 
 #include "Accessible.h"
+#include "AccessibleOrProxy.h"
 
 namespace mozilla {
 namespace a11y {
 
 /**
  * XPCOM wrapper around Accessible class.
  */
 class xpcAccessibleGeneric : public xpcAccessible,
                              public xpcAccessibleHyperLink,
                              public xpcAccessibleSelectable,
                              public xpcAccessibleValue
 {
 public:
   explicit xpcAccessibleGeneric(Accessible* aInternal) :
     mIntl(aInternal), mSupportedIfaces(0)
   {
-    if (mIntl->IsSelect())
+    if (aInternal->IsSelect())
       mSupportedIfaces |= eSelectable;
-    if (mIntl->HasNumericValue())
+    if (aInternal->HasNumericValue())
       mSupportedIfaces |= eValue;
-    if (mIntl->IsLink())
+    if (aInternal->IsLink())
       mSupportedIfaces |= eHyperLink;
   }
 
+  xpcAccessibleGeneric(ProxyAccessible* aProxy, uint32_t aInterfaces) :
+    mIntl(aProxy), mSupportedIfaces(0)
+  {
+    if (aInterfaces & Interfaces::SELECTION) {
+      mSupportedIfaces |= eSelectable;
+    }
+      if (aInterfaces & Interfaces::VALUE) {
+        mSupportedIfaces |= eValue;
+      }
+      if (aInterfaces & Interfaces::HYPERLINK) {
+        mSupportedIfaces |= eHyperLink;
+      }
+    }
+
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(xpcAccessibleGeneric, nsIAccessible)
 
   // nsIAccessible
   virtual Accessible* ToInternalAccessible() const final override;
 
   // xpcAccessibleGeneric
   virtual void Shutdown();
 
 protected:
   virtual ~xpcAccessibleGeneric() {}
 
-  Accessible* mIntl;
+  AccessibleOrProxy mIntl;
 
   enum {
     eSelectable = 1 << 0,
     eValue = 1 << 1,
     eHyperLink = 1 << 2,
     eText = 1 << 3
   };
   uint8_t mSupportedIfaces;
@@ -68,33 +83,39 @@ private:
 
   xpcAccessibleGeneric(const xpcAccessibleGeneric&) = delete;
   xpcAccessibleGeneric& operator =(const xpcAccessibleGeneric&) = delete;
 };
 
 inline Accessible*
 xpcAccessible::Intl()
 {
+  return static_cast<xpcAccessibleGeneric*>(this)->mIntl.AsAccessible();
+}
+
+inline AccessibleOrProxy
+xpcAccessible::IntlGeneric()
+{
   return static_cast<xpcAccessibleGeneric*>(this)->mIntl;
 }
 
 inline Accessible*
 xpcAccessibleHyperLink::Intl()
 {
-  return static_cast<xpcAccessibleGeneric*>(this)->mIntl;
+  return static_cast<xpcAccessibleGeneric*>(this)->mIntl.AsAccessible();
 }
 
 inline Accessible*
 xpcAccessibleSelectable::Intl()
 {
-  return static_cast<xpcAccessibleGeneric*>(this)->mIntl;
+  return static_cast<xpcAccessibleGeneric*>(this)->mIntl.AsAccessible();
 }
 
 inline Accessible*
 xpcAccessibleValue::Intl()
 {
-  return static_cast<xpcAccessibleGeneric*>(this)->mIntl;
+  return static_cast<xpcAccessibleGeneric*>(this)->mIntl.AsAccessible();
 }
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/xpcom/xpcAccessibleHyperText.cpp
+++ b/accessible/xpcom/xpcAccessibleHyperText.cpp
@@ -366,17 +366,17 @@ xpcAccessibleHyperText::GetSelectionRang
   if (!Intl())
     return NS_ERROR_FAILURE;
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsIMutableArray> xpcRanges =
     do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsAutoTArray<TextRange, 1> ranges;
+  AutoTArray<TextRange, 1> ranges;
   Intl()->SelectionRanges(&ranges);
   uint32_t len = ranges.Length();
   for (uint32_t idx = 0; idx < len; idx++)
     xpcRanges->AppendElement(new xpcAccessibleTextRange(Move(ranges[idx])),
                              false);
 
   xpcRanges.forget(aRanges);
   return NS_OK;
--- a/accessible/xpcom/xpcAccessibleHyperText.h
+++ b/accessible/xpcom/xpcAccessibleHyperText.h
@@ -21,31 +21,41 @@ class xpcAccessibleHyperText : public xp
                                public nsIAccessibleText,
                                public nsIAccessibleEditableText,
                                public nsIAccessibleHyperText
 {
 public:
   explicit xpcAccessibleHyperText(Accessible* aIntl) :
     xpcAccessibleGeneric(aIntl)
   {
-    if (mIntl->IsHyperText() && mIntl->AsHyperText()->IsTextRole())
+    if (aIntl->IsHyperText() && aIntl->AsHyperText()->IsTextRole())
       mSupportedIfaces |= eText;
   }
 
+  xpcAccessibleHyperText(ProxyAccessible* aProxy, uint32_t aInterfaces) :
+    xpcAccessibleGeneric(aProxy, aInterfaces) { mSupportedIfaces |= eText; }
+
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIACCESSIBLETEXT
   NS_DECL_NSIACCESSIBLEHYPERTEXT
   NS_DECL_NSIACCESSIBLEEDITABLETEXT
 
 protected:
   virtual ~xpcAccessibleHyperText() {}
 
 private:
-  HyperTextAccessible* Intl() { return mIntl->AsHyperText(); }
+  HyperTextAccessible* Intl()
+  {
+    if (Accessible* acc = mIntl.AsAccessible()) {
+      return acc->AsHyperText();
+    }
+
+    return nullptr;
+  }
 
   xpcAccessibleHyperText(const xpcAccessibleHyperText&) = delete;
   xpcAccessibleHyperText& operator =(const xpcAccessibleHyperText&) = delete;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/xpcom/xpcAccessibleImage.h
+++ b/accessible/xpcom/xpcAccessibleImage.h
@@ -16,27 +16,31 @@ namespace a11y {
 
 class xpcAccessibleImage : public xpcAccessibleGeneric,
                            public nsIAccessibleImage
 {
 public:
   explicit xpcAccessibleImage(Accessible* aIntl) :
     xpcAccessibleGeneric(aIntl) { }
 
+  xpcAccessibleImage(ProxyAccessible* aProxy, uint32_t aInterfaces) :
+    xpcAccessibleGeneric(aProxy, aInterfaces) {}
+
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_IMETHOD GetImagePosition(uint32_t aCoordType,
                               int32_t* aX, int32_t* aY) final override;
   NS_IMETHOD GetImageSize(int32_t* aWidth, int32_t* aHeight) final override;
 
 protected:
   virtual ~xpcAccessibleImage() {}
 
 private:
-  ImageAccessible* Intl() { return mIntl->AsImage(); }
+  ImageAccessible* Intl()
+  { return mIntl.IsAccessible() ? mIntl.AsAccessible()->AsImage() : nullptr; }
 
   xpcAccessibleImage(const xpcAccessibleImage&) = delete;
   xpcAccessibleImage& operator =(const xpcAccessibleImage&) = delete;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/xpcom/xpcAccessibleSelectable.cpp
+++ b/accessible/xpcom/xpcAccessibleSelectable.cpp
@@ -16,17 +16,17 @@ xpcAccessibleSelectable::GetSelectedItem
 {
   NS_ENSURE_ARG_POINTER(aSelectedItems);
   *aSelectedItems = nullptr;
 
   if (!Intl())
     return NS_ERROR_FAILURE;
   NS_PRECONDITION(Intl()->IsSelect(), "Called on non selectable widget!");
 
-  nsAutoTArray<Accessible*, 10> items;
+  AutoTArray<Accessible*, 10> items;
   Intl()->SelectedItems(&items);
 
   uint32_t itemCount = items.Length();
   if (itemCount == 0)
     return NS_OK;
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsIMutableArray> xpcItems =
--- a/accessible/xpcom/xpcAccessibleTable.cpp
+++ b/accessible/xpcom/xpcAccessibleTable.cpp
@@ -268,17 +268,17 @@ xpcAccessibleTable::GetSelectedCells(nsI
   if (!Intl())
     return NS_ERROR_FAILURE;
 
   nsresult rv = NS_OK;
   nsCOMPtr<nsIMutableArray> selCells =
     do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsAutoTArray<Accessible*, XPC_TABLE_DEFAULT_SIZE> cellsArray;
+  AutoTArray<Accessible*, XPC_TABLE_DEFAULT_SIZE> cellsArray;
   Intl()->SelectedCells(&cellsArray);
 
   uint32_t totalCount = cellsArray.Length();
   for (uint32_t idx = 0; idx < totalCount; idx++) {
     Accessible* cell = cellsArray.ElementAt(idx);
     selCells->AppendElement(static_cast<nsIAccessible*>(ToXPC(cell)), false);
   }
 
@@ -294,17 +294,17 @@ xpcAccessibleTable::GetSelectedCellIndic
   *aCellsArraySize = 0;
 
   NS_ENSURE_ARG_POINTER(aCellsArray);
   *aCellsArray = 0;
 
   if (!Intl())
     return NS_ERROR_FAILURE;
 
-  nsAutoTArray<uint32_t, XPC_TABLE_DEFAULT_SIZE> cellsArray;
+  AutoTArray<uint32_t, XPC_TABLE_DEFAULT_SIZE> cellsArray;
   Intl()->SelectedCellIndices(&cellsArray);
 
   *aCellsArraySize = cellsArray.Length();
   *aCellsArray = static_cast<int32_t*>
     (moz_xmalloc(*aCellsArraySize * sizeof(int32_t)));
   memcpy(*aCellsArray, cellsArray.Elements(),
     *aCellsArraySize * sizeof(int32_t));
 
@@ -319,17 +319,17 @@ xpcAccessibleTable::GetSelectedColumnInd
   *aColsArraySize = 0;
 
   NS_ENSURE_ARG_POINTER(aColsArray);
   *aColsArray = 0;
 
   if (!Intl())
     return NS_ERROR_FAILURE;
 
-  nsAutoTArray<uint32_t, XPC_TABLE_DEFAULT_SIZE> colsArray;
+  AutoTArray<uint32_t, XPC_TABLE_DEFAULT_SIZE> colsArray;
   Intl()->SelectedColIndices(&colsArray);
 
   *aColsArraySize = colsArray.Length();
   *aColsArray = static_cast<int32_t*>
     (moz_xmalloc(*aColsArraySize * sizeof(int32_t)));
   memcpy(*aColsArray, colsArray.Elements(),
     *aColsArraySize * sizeof(int32_t));
 
@@ -344,17 +344,17 @@ xpcAccessibleTable::GetSelectedRowIndice
   *aRowsArraySize = 0;
 
   NS_ENSURE_ARG_POINTER(aRowsArray);
   *aRowsArray = 0;
 
   if (!Intl())
     return NS_ERROR_FAILURE;
 
-  nsAutoTArray<uint32_t, XPC_TABLE_DEFAULT_SIZE> rowsArray;
+  AutoTArray<uint32_t, XPC_TABLE_DEFAULT_SIZE> rowsArray;
   Intl()->SelectedRowIndices(&rowsArray);
 
   *aRowsArraySize = rowsArray.Length();
   *aRowsArray = static_cast<int32_t*>
     (moz_xmalloc(*aRowsArraySize * sizeof(int32_t)));
   memcpy(*aRowsArray, rowsArray.Elements(),
     *aRowsArraySize * sizeof(int32_t));
 
--- a/accessible/xpcom/xpcAccessibleTable.h
+++ b/accessible/xpcom/xpcAccessibleTable.h
@@ -18,16 +18,19 @@ namespace a11y {
  */
 class xpcAccessibleTable : public xpcAccessibleGeneric,
                            public nsIAccessibleTable
 {
 public:
   explicit xpcAccessibleTable(Accessible* aIntl) :
     xpcAccessibleGeneric(aIntl) { }
 
+  xpcAccessibleTable(ProxyAccessible* aProxy, uint32_t aInterfaces) :
+    xpcAccessibleGeneric(aProxy, aInterfaces) {}
+
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessibleTable
   NS_IMETHOD GetCaption(nsIAccessible** aCaption) final override;
   NS_IMETHOD GetSummary(nsAString& aSummary) final override;
   NS_IMETHOD GetColumnCount(int32_t* aColumnCount) final override;
   NS_IMETHOD GetRowCount(int32_t* aRowCount) final override;
   NS_IMETHOD GetCellAt(int32_t aRowIndex, int32_t aColumnIndex,
@@ -75,17 +78,18 @@ public:
   NS_IMETHOD UnselectColumn(int32_t aColIdx) final override;
   NS_IMETHOD UnselectRow(int32_t aRowIdx) final override;
   NS_IMETHOD IsProbablyForLayout(bool* aIsForLayout) final override;
 
 protected:
   virtual ~xpcAccessibleTable() {}
 
 private:
-  TableAccessible* Intl() { return mIntl->AsTable(); }
+  TableAccessible* Intl()
+  { return mIntl.IsAccessible() ? mIntl.AsAccessible()->AsTable() : nullptr; }
 
   xpcAccessibleTable(const xpcAccessibleTable&) = delete;
   xpcAccessibleTable& operator =(const xpcAccessibleTable&) = delete;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/xpcom/xpcAccessibleTableCell.cpp
+++ b/accessible/xpcom/xpcAccessibleTableCell.cpp
@@ -103,17 +103,17 @@ NS_IMETHODIMP
 xpcAccessibleTableCell::GetColumnHeaderCells(nsIArray** aHeaderCells)
 {
   NS_ENSURE_ARG_POINTER(aHeaderCells);
   *aHeaderCells = nullptr;
 
   if (!Intl())
     return NS_ERROR_FAILURE;
 
-  nsAutoTArray<Accessible*, 10> headerCells;
+  AutoTArray<Accessible*, 10> headerCells;
   Intl()->ColHeaderCells(&headerCells);
 
   nsCOMPtr<nsIMutableArray> cells = do_CreateInstance(NS_ARRAY_CONTRACTID);
   NS_ENSURE_TRUE(cells, NS_ERROR_FAILURE);
 
   for (uint32_t idx = 0; idx < headerCells.Length(); idx++) {
     cells->AppendElement(static_cast<nsIAccessible*>(ToXPC(headerCells[idx])),
                          false);
@@ -127,17 +127,17 @@ NS_IMETHODIMP
 xpcAccessibleTableCell::GetRowHeaderCells(nsIArray** aHeaderCells)
 {
   NS_ENSURE_ARG_POINTER(aHeaderCells);
   *aHeaderCells = nullptr;
 
   if (!Intl())
     return NS_ERROR_FAILURE;
 
-  nsAutoTArray<Accessible*, 10> headerCells;
+  AutoTArray<Accessible*, 10> headerCells;
   Intl()->RowHeaderCells(&headerCells);
 
   nsCOMPtr<nsIMutableArray> cells = do_CreateInstance(NS_ARRAY_CONTRACTID);
   NS_ENSURE_TRUE(cells, NS_ERROR_FAILURE);
 
   for (uint32_t idx = 0; idx < headerCells.Length(); idx++) {
     cells->AppendElement(static_cast<nsIAccessible*>(ToXPC(headerCells[idx])),
                          false);
--- a/accessible/xpcom/xpcAccessibleTableCell.h
+++ b/accessible/xpcom/xpcAccessibleTableCell.h
@@ -19,33 +19,43 @@ namespace a11y {
  */
 class xpcAccessibleTableCell : public xpcAccessibleHyperText,
                                public nsIAccessibleTableCell
 {
 public:
   explicit xpcAccessibleTableCell(Accessible* aIntl) :
     xpcAccessibleHyperText(aIntl) { }
 
+  xpcAccessibleTableCell(ProxyAccessible* aProxy, uint32_t aInterfaces) :
+    xpcAccessibleHyperText(aProxy, aInterfaces) {}
+
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessibleTableCell
   NS_IMETHOD GetTable(nsIAccessibleTable** aTable) final override;
   NS_IMETHOD GetColumnIndex(int32_t* aColIdx) final override;
   NS_IMETHOD GetRowIndex(int32_t* aRowIdx) final override;
   NS_IMETHOD GetColumnExtent(int32_t* aExtent) final override;
   NS_IMETHOD GetRowExtent(int32_t* aExtent) final override;
   NS_IMETHOD GetColumnHeaderCells(nsIArray** aHeaderCells) final override;
   NS_IMETHOD GetRowHeaderCells(nsIArray** aHeaderCells) final override;
   NS_IMETHOD IsSelected(bool* aSelected) final override;
 
 protected:
   virtual ~xpcAccessibleTableCell() {}
 
 private:
-  TableCellAccessible* Intl() { return mIntl->AsTableCell(); }
+  TableCellAccessible* Intl()
+  {
+    if (Accessible* acc = mIntl.AsAccessible()) {
+      return acc->AsTableCell();
+    }
+
+    return nullptr;
+}
 
   xpcAccessibleTableCell(const xpcAccessibleTableCell&) = delete;
   xpcAccessibleTableCell& operator =(const xpcAccessibleTableCell&) = delete;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/addon-sdk/source/lib/toolkit/loader.js
+++ b/addon-sdk/source/lib/toolkit/loader.js
@@ -278,17 +278,17 @@ const evaluate = iced(function evaluate(
   return source ? Cu.evalInSandbox(source, sandbox, version, uri, line)
                 : loadSubScript(uri, sandbox, encoding);
 });
 Loader.evaluate = evaluate;
 
 // Populates `exports` of the given CommonJS `module` object, in the context
 // of the given `loader` by evaluating code associated with it.
 const load = iced(function load(loader, module) {
-  let { sandboxes, globals } = loader;
+  let { sandboxes, globals, loadModuleHook } = loader;
   let require = Require(loader, module);
 
   // We expose set of properties defined by `CommonJS` specification via
   // prototype of the sandbox. Also globals are deeper in the prototype
   // chain so that each module has access to them as well.
   let descriptors = descriptor({
     require: require,
     module: module,
@@ -297,17 +297,17 @@ const load = iced(function load(loader, 
       // Expose `Components` property to throw error on usage with
       // additional information
       throw new ReferenceError(COMPONENT_ERROR);
     }
   });
 
   let sandbox;
   if (loader.sharedGlobalSandbox &&
-      loader.sharedGlobalBlacklist.indexOf(module.id) == -1) {
+      loader.sharedGlobalBlocklist.indexOf(module.id) == -1) {
     // Create a new object in this sandbox, that will be used as
     // the scope object for this particular module
     sandbox = new loader.sharedGlobalSandbox.Object();
     // Inject all expected globals in the scope object
     getOwnIdentifiers(globals).forEach(function(name) {
       descriptors[name] = getOwnPropertyDescriptor(globals, name)
     });
     define(sandbox, descriptors);
@@ -363,16 +363,20 @@ const load = iced(function load(loader, 
       message: { value: message, writable: true, configurable: true },
       fileName: { value: fileName, writable: true, configurable: true },
       lineNumber: { value: lineNumber, writable: true, configurable: true },
       stack: { value: serializeStack(frames), writable: true, configurable: true },
       toString: { value: () => toString, writable: true, configurable: true },
     });
   }
 
+  if(loadModuleHook) {
+    module = loadModuleHook(module, require);
+  }
+
   if (loader.checkCompatibility) {
     let err = XulApp.incompatibility(module);
     if (err) {
       throw err;
     }
   }
 
   if (module.exports && typeof(module.exports) === 'object')
@@ -583,26 +587,26 @@ Loader.resolveURI = resolveURI;
 // Creates version of `require` that will be exposed to the given `module`
 // in the context of the given `loader`. Each module gets own limited copy
 // of `require` that is allowed to load only a modules that are associated
 // with it during link time.
 const Require = iced(function Require(loader, requirer) {
   let {
     modules, mapping, resolve: loaderResolve, load,
     manifest, rootURI, isNative, requireMap,
-    overrideRequire
+    requireHook
   } = loader;
 
   function require(id) {
     if (!id) // Throw if `id` is not passed.
       throw Error('You must provide a module name when calling require() from '
                   + requirer.id, requirer.uri);
 
-    if (overrideRequire) {
-      return overrideRequire(id, _require);
+    if (requireHook) {
+      return requireHook(id, _require);
     }
 
     return _require(id);
   }
 
   function _require(id) {
     let { uri, requirement } = getRequirements(id);
     let module = null;
@@ -801,19 +805,22 @@ Loader.unload = unload;
 //   These modules will incorporated into module cache. Each module will be
 //   frozen.
 // - `resolve` Optional module `id` resolution function. If given it will be
 //   used to resolve module URIs, by calling it with require term, requirer
 //   module object (that has `uri` property) and `baseURI` of the loader.
 //   If `resolve` does not returns `uri` string exception will be thrown by
 //   an associated `require` call.
 function Loader(options) {
+  if (options.sharedGlobalBlacklist && !options.sharedGlobalBlocklist) {
+    options.sharedGlobalBlocklist = options.sharedGlobalBlacklist;
+  }
   let {
     modules, globals, resolve, paths, rootURI, manifest, requireMap, isNative,
-    metadata, sharedGlobal, sharedGlobalBlacklist, checkCompatibility, waiveIntereposition
+    metadata, sharedGlobal, sharedGlobalBlocklist, checkCompatibility, waiveIntereposition
   } = override({
     paths: {},
     modules: {},
     globals: {
       get console() {
         // Import Console.jsm from here to prevent loading it until someone uses it
         let { ConsoleAPI } = Cu.import("resource://gre/modules/Console.jsm");
         let console = new ConsoleAPI({
@@ -823,17 +830,17 @@ function Loader(options) {
         return this.console;
       }
     },
     checkCompatibility: false,
     resolve: options.isNative ?
       // Make the returned resolve function have the same signature
       (id, requirer) => Loader.nodeResolve(id, requirer, { rootURI: rootURI }) :
       Loader.resolve,
-    sharedGlobalBlacklist: ["sdk/indexed-db"],
+    sharedGlobalBlocklist: ["sdk/indexed-db"],
     waiveIntereposition: false
   }, options);
 
   // Create overrides defaults, none at the moment
   if (typeof manifest != "object" || !manifest) {
     manifest = {};
   }
   if (typeof manifest.jetpack != "object" || !manifest.jetpack) {
@@ -914,28 +921,30 @@ function Loader(options) {
   let returnObj = {
     destructor: { enumerable: false, value: destructor },
     globals: { enumerable: false, value: globals },
     mapping: { enumerable: false, value: mapping },
     // Map of module objects indexed by module URIs.
     modules: { enumerable: false, value: modules },
     metadata: { enumerable: false, value: metadata },
     sharedGlobalSandbox: { enumerable: false, value: sharedGlobalSandbox },
-    sharedGlobalBlacklist: { enumerable: false, value: sharedGlobalBlacklist },
+    sharedGlobalBlocklist: { enumerable: false, value: sharedGlobalBlocklist },
+    sharedGlobalBlacklist: { enumerable: false, value: sharedGlobalBlocklist },
     // Map of module sandboxes indexed by module URIs.
     sandboxes: { enumerable: false, value: {} },
     resolve: { enumerable: false, value: resolve },
     // ID of the addon, if provided.
     id: { enumerable: false, value: options.id },
     // Whether the modules loaded should be ignored by the debugger
     invisibleToDebugger: { enumerable: false,
                            value: options.invisibleToDebugger || false },
     load: { enumerable: false, value: options.load || load },
     checkCompatibility: { enumerable: false, value: checkCompatibility },
-    overrideRequire: { enumerable: false, value: options.require },
+    requireHook: { enumerable: false, value: options.requireHook },
+    loadModuleHook: { enumerable: false, value: options.loadModuleHook },
     // Main (entry point) module, it can be set only once, since loader
     // instance can have only one main module.
     main: new function() {
       let main;
       return {
         enumerable: false,
         get: function() { return main; },
         // Only set main if it has not being set yet!
--- a/addon-sdk/source/test/sidebar/utils.js
+++ b/addon-sdk/source/test/sidebar/utils.js
@@ -12,16 +12,17 @@ module.metadata = {
 const { Cu } = require('chrome');
 const { getMostRecentBrowserWindow } = require('sdk/window/utils');
 const { fromIterator } = require('sdk/util/array');
 
 const BUILTIN_SIDEBAR_MENUITEMS = exports.BUILTIN_SIDEBAR_MENUITEMS = [
   'menu_socialSidebar',
   'menu_historySidebar',
   'menu_bookmarksSidebar',
+  'menu_tabsSidebar',
 ];
 
 function isSidebarShowing(window) {
   window = window || getMostRecentBrowserWindow();
   let sidebar = window.document.getElementById('sidebar-box');
   return !sidebar.hidden;
 }
 exports.isSidebarShowing = isSidebarShowing;
--- a/addon-sdk/source/test/test-loader.js
+++ b/addon-sdk/source/test/test-loader.js
@@ -346,20 +346,49 @@ exports['test console global by default'
   assert.equal(program2.console, fakeConsole,
     'global console can be overridden with Loader options');
   function fakeConsole () {};
 };
 
 exports['test shared globals'] = function(assert) {
   let uri = root + '/fixtures/loader/cycles/';
   let loader = Loader({ paths: { '': uri }, sharedGlobal: true,
+                        sharedGlobalBlocklist: ['b'] });
+
+  let program = main(loader, 'main');
+
+  // As it is hard to verify what is the global of an object
+  // (due to wrappers) we check that we see the `foo` symbol
+  // being manually injected into the shared global object
+  loader.sharedGlobalSandbox.foo = true;
+
+  let m = loader.sandboxes[uri + 'main.js'];
+  let a = loader.sandboxes[uri + 'a.js'];
+  let b = loader.sandboxes[uri + 'b.js'];
+
+  assert.ok(Cu.getGlobalForObject(m).foo, "main is shared");
+  assert.ok(Cu.getGlobalForObject(a).foo, "a is shared");
+  assert.ok(!Cu.getGlobalForObject(b).foo, "b isn't shared");
+
+  unload(loader);
+}
+
+exports['test deprecated shared globals exception name'] = function(assert) {
+  let uri = root + '/fixtures/loader/cycles/';
+  let loader = Loader({ paths: { '': uri }, sharedGlobal: true,
                         sharedGlobalBlacklist: ['b'] });
 
   let program = main(loader, 'main');
 
+  assert.ok(loader.sharedGlobalBlocklist.includes("b"), "b should be in the blocklist");
+  assert.equal(loader.sharedGlobalBlocklist.length, loader.sharedGlobalBlacklist.length,
+               "both blocklists should have the same number of items.");
+  assert.equal(loader.sharedGlobalBlocklist.join(","), loader.sharedGlobalBlacklist.join(","),
+               "both blocklists should have the same items.");
+
   // As it is hard to verify what is the global of an object
   // (due to wrappers) we check that we see the `foo` symbol
   // being manually injected into the shared global object
   loader.sharedGlobalSandbox.foo = true;
 
   let m = loader.sandboxes[uri + 'main.js'];
   let a = loader.sandboxes[uri + 'a.js'];
   let b = loader.sandboxes[uri + 'b.js'];
@@ -567,17 +596,17 @@ exports['test user global'] = function(a
 
   assert.equal(userModule.getCom(), com,
                "user module returns expected `com` global");
 };
 
 exports['test custom require caching'] = function(assert) {
   const loader = Loader({
     paths: { '': root + "/" },
-    require: (id, require) => {
+    requireHook: (id, require) => {
       // Just load it normally
       return require(id);
     }
   });
   const require = Require(loader, module);
 
   let data = require('fixtures/loader/json/mutation.json');
   assert.equal(data.value, 1, 'has initial value');
@@ -589,17 +618,17 @@ exports['test custom require caching'] =
     'JSON objects returned should be cached and the same instance'
   );
 };
 
 exports['test caching when proxying a loader'] = function(assert) {
   const parentRequire = require;
   const loader = Loader({
     paths: { '': root + "/" },
-    require: (id, childRequire) => {
+    requireHook: (id, childRequire) => {
       if(id === 'gimmejson') {
         return childRequire('fixtures/loader/json/mutation.json')
       }
       // Load it with the original (global) require
       return parentRequire(id);
     }
   });
   const childRequire = Require(loader, module);
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -350,16 +350,20 @@ pref("dom.w3c_touch_events.safetyY", 120
 #ifdef MOZ_SAFE_BROWSING
 pref("browser.safebrowsing.enabled", true);
 // Prevent loading of pages identified as malware
 pref("browser.safebrowsing.malware.enabled", true);
 pref("browser.safebrowsing.downloads.enabled", true);
 pref("browser.safebrowsing.downloads.remote.enabled", true);
 pref("browser.safebrowsing.downloads.remote.timeout_ms", 10000);
 pref("browser.safebrowsing.downloads.remote.url", "https://sb-ssl.google.com/safebrowsing/clientreport/download?key=%GOOGLE_API_KEY%");
+pref("browser.safebrowsing.downloads.remote.block_dangerous",            true);
+pref("browser.safebrowsing.downloads.remote.block_dangerous_host",       true);
+pref("browser.safebrowsing.downloads.remote.block_potentially_unwanted", false);
+pref("browser.safebrowsing.downloads.remote.block_uncommon",             false);
 pref("browser.safebrowsing.debug", false);
 
 pref("browser.safebrowsing.provider.google.lists", "goog-badbinurl-shavar,goog-downloadwhite-digest256,goog-phish-shavar,goog-malware-shavar,goog-unwanted-shavar");
 pref("browser.safebrowsing.provider.google.updateURL", "https://safebrowsing.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2&key=%GOOGLE_API_KEY%");
 pref("browser.safebrowsing.provider.google.gethashURL", "https://safebrowsing.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
 pref("browser.safebrowsing.provider.google.reportURL", "https://safebrowsing.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
 
 pref("browser.safebrowsing.reportPhishMistakeURL", "https://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%&url=");
@@ -1006,16 +1010,17 @@ pref("dom.downloads.max_retention_days",
 //
 // To prevent SD card DoS attacks via downloads we disable background handling.
 //
 pref("security.exthelperapp.disable_background_handling", true);
 
 // Inactivity time in milliseconds after which we shut down the OS.File worker.
 pref("osfile.reset_worker_delay", 5000);
 
+pref("apz.displayport_expiry_ms", 0);
 // APZ physics settings, tuned by UX designers
 pref("apz.axis_lock.mode", 2); // Use "sticky" axis locking
 pref("apz.fling_curve_function_x1", "0.41");
 pref("apz.fling_curve_function_y1", "0.0");
 pref("apz.fling_curve_function_x2", "0.80");
 pref("apz.fling_curve_function_y2", "1.0");
 pref("apz.fling_curve_threshold_inches_per_ms", "0.01");
 pref("apz.fling_friction", "0.0019");
new file mode 100644
--- /dev/null
+++ b/b2g/branding/branding-common.mozbuild
@@ -0,0 +1,24 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+@template
+def B2GBranding():
+    if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
+        BRANDING_FILES += [
+            'app.ico',
+        ]
+    elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
+        BRANDING_FILES += [
+            'app.icns',
+            'background.png',
+            'disk.icns',
+            'dsstore',
+        ]
+
+    if CONFIG['MOZ_WIDGET_GTK']:
+        BRANDING_FILES += [
+            'default.png',
+        ]
deleted file mode 100644
--- a/b2g/branding/browserhtml/Makefile.in
+++ /dev/null
@@ -1,30 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-include $(topsrcdir)/config/config.mk
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
-BRANDING_FILES := \
-	app.ico \
-	$(NULL)
-endif
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
-BRANDING_FILES := \
-	app.icns \
-	background.png \
-	disk.icns \
-	dsstore \
-	$(NULL)
-endif
-
-ifdef MOZ_WIDGET_GTK
-BRANDING_FILES := \
-	default.png \
-	$(NULL)
-endif
-
-BRANDING_DEST := $(DIST)/branding
-BRANDING_TARGET := export
-INSTALL_TARGETS += BRANDING
--- a/b2g/branding/browserhtml/moz.build
+++ b/b2g/branding/browserhtml/moz.build
@@ -1,7 +1,10 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['content', 'locales']
+
+include('../branding-common.mozbuild')
+B2GBranding()
deleted file mode 100644
--- a/b2g/branding/horizon/Makefile.in
+++ /dev/null
@@ -1,30 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-include $(topsrcdir)/config/config.mk
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
-BRANDING_FILES := \
-	app.ico \
-	$(NULL)
-endif
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
-BRANDING_FILES := \
-	app.icns \
-	background.png \
-	disk.icns \
-	dsstore \
-	$(NULL)
-endif
-
-ifdef MOZ_WIDGET_GTK
-BRANDING_FILES := \
-	default.png \
-	$(NULL)
-endif
-
-BRANDING_DEST := $(DIST)/branding
-BRANDING_TARGET := export
-INSTALL_TARGETS += BRANDING
--- a/b2g/branding/horizon/moz.build
+++ b/b2g/branding/horizon/moz.build
@@ -1,7 +1,10 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['content', 'locales']
+
+include('../branding-common.mozbuild')
+B2GBranding()
deleted file mode 100644
--- a/b2g/branding/official/Makefile.in
+++ /dev/null
@@ -1,30 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-include $(topsrcdir)/config/config.mk
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
-BRANDING_FILES := \
-	app.ico \
-	$(NULL)
-endif
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
-BRANDING_FILES := \
-	app.icns \
-	background.png \
-	disk.icns \
-	dsstore \
-	$(NULL)
-endif
-
-ifdef MOZ_WIDGET_GTK
-BRANDING_FILES := \
-	default.png \
-	$(NULL)
-endif
-
-BRANDING_DEST := $(DIST)/branding
-BRANDING_TARGET := export
-INSTALL_TARGETS += BRANDING
--- a/b2g/branding/official/moz.build
+++ b/b2g/branding/official/moz.build
@@ -1,7 +1,10 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['content', 'locales']
+
+include('../branding-common.mozbuild')
+B2GBranding()
deleted file mode 100644
--- a/b2g/branding/unofficial/Makefile.in
+++ /dev/null
@@ -1,30 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-include $(topsrcdir)/config/config.mk
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
-BRANDING_FILES := \
-	app.ico \
-	$(NULL)
-endif
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
-BRANDING_FILES := \
-	app.icns \
-	background.png \
-	disk.icns \
-	dsstore \
-	$(NULL)
-endif
-
-ifdef MOZ_WIDGET_GTK
-BRANDING_FILES := \
-	default.png \
-	$(NULL)
-endif
-
-BRANDING_DEST := $(DIST)/branding
-BRANDING_TARGET := export
-INSTALL_TARGETS += BRANDING
--- a/b2g/branding/unofficial/moz.build
+++ b/b2g/branding/unofficial/moz.build
@@ -1,7 +1,10 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['content', 'locales']
+
+include('../branding-common.mozbuild')
+B2GBranding()
--- a/b2g/components/PersistentDataBlock.jsm
+++ b/b2g/components/PersistentDataBlock.jsm
@@ -61,17 +61,17 @@ function debug(str) {
 
 function toHexString(data) {
   function toHexChar(charCode) {
     return ("0" + charCode.toString(16).slice(-2));
   }
   let hexString = "";
   if (typeof data === "string") {
     hexString = Array.from(data, (c, i) => toHexChar(data.charCodeAt(i))).join("");
-  } else if (typeof data === "array") {
+  } else if (data instanceof Array) {
     hexString = data.map(toHexChar).join("");
   }
   return hexString;
 }
 
 function arr2bstr(arr) {
   let bstr = "";
   for (let i = 0; i < arr.length; i++) {
--- a/b2g/components/test/unit/file_persistentdatablock.js
+++ b/b2g/components/test/unit/file_persistentdatablock.js
@@ -28,17 +28,17 @@ function log(str) {
 
 function toHexString(data) {
   function toHexChar(charCode) {
     return ("0" + charCode.toString(16).slice(-2));
   }
   let hexString = "";
   if (typeof data === "string") {
     hexString = Array.from(data, (c, i) => toHexChar(data.charCodeAt(i))).join("");
-  } else if (typeof data === "array") {
+  } else if (data instanceof Array) {
     hexString = data.map(toHexChar).join("");
   }
   return hexString;
 }
 
 function _prepareConfig(_args) {
   let args = _args || {};
   // This digest has been previously calculated given the data to be written later, and setting the OEM Unlocked Enabled byte
--- a/b2g/installer/Makefile.in
+++ b/b2g/installer/Makefile.in
@@ -21,27 +21,24 @@ DEFINES += \
 	-DPREF_DIR=$(PREF_DIR) \
 	$(NULL)
 
 DEFINES += -DJAREXT=
 
 DEFINES += -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME)
 
 # Set MSVC dlls version to package, if any.
+ifdef MOZ_NO_DEBUG_RTL
 ifdef WIN32_REDIST_DIR
-ifdef MOZ_NO_DEBUG_RTL
 DEFINES += -DMOZ_PACKAGE_MSVC_DLLS=1
 DEFINES += -DMSVC_C_RUNTIME_DLL=$(MSVC_C_RUNTIME_DLL)
 DEFINES += -DMSVC_CXX_RUNTIME_DLL=$(MSVC_CXX_RUNTIME_DLL)
-ifdef MSVC_APPCRT_DLL
-DEFINES += -DMSVC_APPCRT_DLL=$(MSVC_APPCRT_DLL)
 endif
-ifdef MSVC_DESKTOPCRT_DLL
-DEFINES += -DMSVC_DESKTOPCRT_DLL=$(MSVC_DESKTOPCRT_DLL)
-endif
+ifdef WIN_UCRT_REDIST_DIR
+DEFINES += -DMOZ_PACKAGE_WIN_UCRT_DLLS=1
 endif
 endif
 
 ifdef MOZ_DEBUG
 DEFINES += -DMOZ_DEBUG=1
 endif
 
 ifdef ENABLE_MARIONETTE
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -60,22 +60,20 @@
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@.app/
 #else
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@
 #endif
 #ifdef XP_WIN32
 #if MOZ_PACKAGE_MSVC_DLLS
 @BINPATH@/@MSVC_C_RUNTIME_DLL@
 @BINPATH@/@MSVC_CXX_RUNTIME_DLL@
-#ifdef MSVC_APPCRT_DLL
-@BINPATH@/@MSVC_APPCRT_DLL@
 #endif
-#ifdef MSVC_DESKTOPCRT_DLL
-@BINPATH@/@MSVC_DESKTOPCRT_DLL@
-#endif
+#if MOZ_PACKAGE_WIN_UCRT_DLLS
+@BINPATH@/api-ms-win-*.dll
+@BINPATH@/ucrtbase.dll
 #endif
 #endif
 #ifndef MOZ_NATIVE_ICU
 #ifdef MOZ_SHARED_ICU
 #ifdef XP_WIN
 @BINPATH@/icudt@MOZ_ICU_DBG_SUFFIX@@MOZ_ICU_VERSION@.dll
 @BINPATH@/icuin@MOZ_ICU_DBG_SUFFIX@@MOZ_ICU_VERSION@.dll
 @BINPATH@/icuuc@MOZ_ICU_DBG_SUFFIX@@MOZ_ICU_VERSION@.dll
@@ -242,17 +240,16 @@
 @RESPATH@/components/exthandler.xpt
 @RESPATH@/components/exthelper.xpt
 @RESPATH@/components/fastfind.xpt
 @RESPATH@/components/feeds.xpt
 #ifdef MOZ_GTK
 @RESPATH@/components/filepicker.xpt
 #endif
 @RESPATH@/components/find.xpt
-@RESPATH@/components/fuel.xpt
 @RESPATH@/components/gfx.xpt
 @RESPATH@/components/hal.xpt
 @RESPATH@/components/html5.xpt
 @RESPATH@/components/htmlparser.xpt
 @RESPATH@/components/identity.xpt
 @RESPATH@/components/imglib2.xpt
 @RESPATH@/components/inspector.xpt
 @RESPATH@/components/intl.xpt
@@ -321,16 +318,17 @@
 @RESPATH@/components/spellchecker.xpt
 @RESPATH@/components/storage.xpt
 @RESPATH@/components/telemetry.xpt
 @RESPATH@/components/toolkit_asyncshutdown.xpt
 @RESPATH@/components/toolkit_filewatcher.xpt
 @RESPATH@/components/toolkit_finalizationwitness.xpt
 @RESPATH@/components/toolkit_formautofill.xpt
 @RESPATH@/components/toolkit_osfile.xpt
+@RESPATH@/components/toolkit_securityreporter.xpt
 #ifdef NIGHTLY_BUILD
 @RESPATH@/components/toolkit_perfmonitoring.xpt
 #endif
 @RESPATH@/components/toolkit_xulstore.xpt
 @RESPATH@/components/toolkitprofile.xpt
 #ifdef MOZ_ENABLE_XREMOTE
 @RESPATH@/components/toolkitremote.xpt
 #endif
@@ -395,18 +393,16 @@
 @RESPATH@/components/AlarmsManager.manifest
 @RESPATH@/components/FeedProcessor.manifest
 @RESPATH@/components/FeedProcessor.js
 @RESPATH@/components/PackagedAppUtils.manifest
 @RESPATH@/components/PackagedAppUtils.js
 @RESPATH@/components/BrowserFeeds.manifest
 @RESPATH@/components/FeedConverter.js
 @RESPATH@/components/FeedWriter.js
-@RESPATH@/components/fuelApplication.manifest
-@RESPATH@/components/fuelApplication.js
 @RESPATH@/components/WebContentConverter.js
 @RESPATH@/components/BrowserComponents.manifest
 @RESPATH@/components/nsBrowserContentHandler.js
 @RESPATH@/components/nsBrowserGlue.js
 @RESPATH@/components/nsSetDefaultBrowser.manifest
 @RESPATH@/components/nsSetDefaultBrowser.js
 @RESPATH@/components/toolkitsearch.manifest
 @RESPATH@/components/nsTryToClose.manifest
@@ -705,16 +701,20 @@
 @RESPATH@/components/nsUrlClassifierLib.js
 @RESPATH@/components/url-classifier.xpt
 
 ; Private Browsing
 @RESPATH@/components/privatebrowsing.xpt
 @RESPATH@/components/PrivateBrowsing.manifest
 @RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
 
+; Security Reports
+@RESPATH@/components/SecurityReporter.manifest
+@RESPATH@/components/SecurityReporter.js
+
 ; Signed Packaged Content
 @RESPATH@/components/InstallPackagedWebapp.manifest
 @RESPATH@/components/InstallPackagedWebapp.js
 
 ; ANGLE on Win32
 #ifdef XP_WIN32
 #ifndef HAVE_64BIT_BUILD
 @BINPATH@/libEGL.dll
--- a/browser/.eslintrc
+++ b/browser/.eslintrc
@@ -1,13 +1,5 @@
 {
   "extends": [
     "../toolkit/.eslintrc"
   ],
-
-  "rules": {
-    // No redeclaring variables
-    "no-redeclare": 2,
-
-    // Functions must always return something or nothing
-    "consistent-return": 2,
-  }
 }
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -2,24 +2,16 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 dist_dest   = $(DIST)/$(MOZ_MACBUNDLE_NAME)
 
 # hardcode en-US for the moment
 AB_CD = en-US
 
-DEFINES += \
-  -DFIREFOX_ICO='"$(DIST)/branding/firefox.ico"' \
-  -DDOCUMENT_ICO='"$(DIST)/branding/document.ico"' \
-  -DNEWWINDOW_ICO='"$(DIST)/branding/newwindow.ico"' \
-  -DNEWTAB_ICO='"$(DIST)/branding/newtab.ico"' \
-  -DPBMODE_ICO='"$(DIST)/branding/pbmode.ico"' \
-  $(NULL)
-
 # Build a binary bootstrapping with XRE_main
 
 ifndef MOZ_WINCONSOLE
 ifneq (,$(MOZ_DEBUG)$(MOZ_ASAN))
 MOZ_WINCONSOLE = 1
 else
 MOZ_WINCONSOLE = 0
 endif
--- a/browser/app/moz.build
+++ b/browser/app/moz.build
@@ -68,8 +68,12 @@ DISABLE_STL_WRAPPING = True
 if CONFIG['MOZ_LINKER']:
     OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']
 
 if CONFIG['HAVE_CLOCK_MONOTONIC']:
     OS_LIBS += CONFIG['REALTIME_LIBS']
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wshadow']
+
+for icon in ('firefox', 'document', 'newwindow', 'newtab', 'pbmode'):
+    DEFINES[icon.upper() + '_ICO'] = '"%s/dist/branding/%s.ico"' % (
+        TOPOBJDIR, icon)
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -207,16 +207,18 @@ pref("browser.eme.ui.enabled", false);
 // UI tour experience.
 pref("browser.uitour.enabled", true);
 pref("browser.uitour.loglevel", "Error");
 pref("browser.uitour.requireSecure", true);
 pref("browser.uitour.themeOrigin", "https://addons.mozilla.org/%LOCALE%/firefox/themes/");
 pref("browser.uitour.url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/tour/");
 // This is used as a regexp match against the page's URL.
 pref("browser.uitour.readerViewTrigger", "^https:\\/\\/www\\.mozilla\\.org\\/[^\\/]+\\/firefox\\/reading\\/start");
+// How long to show a Hearbeat survey (two hours, in seconds)
+pref("browser.uitour.surveyDuration", 7200);
 
 pref("browser.customizemode.tip0.shown", false);
 pref("browser.customizemode.tip0.learnMoreUrl", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/customize");
 
 pref("keyword.enabled", true);
 pref("browser.fixup.domainwhitelist.localhost", true);
 
 pref("general.useragent.locale", "@AB_CD@");
@@ -522,18 +524,16 @@ pref("privacy.cpd.openWindows",         
 // 4 - Today
 // 5 - Last 5 minutes
 // 6 - Last 24 hours
 pref("privacy.sanitize.timeSpan", 1);
 pref("privacy.sanitize.sanitizeOnShutdown", false);
 
 pref("privacy.sanitize.migrateFx3Prefs",    false);
 
-pref("privacy.sanitize.migrateClearSavedPwdsOnExit", false);
-
 pref("privacy.panicButton.enabled",         true);
 
 pref("network.proxy.share_proxy_settings",  false); // use the same proxy settings for all protocols
 
 // simple gestures support
 pref("browser.gesture.swipe.left", "Browser:BackOrBackDuplicate");
 pref("browser.gesture.swipe.right", "Browser:ForwardOrForwardDuplicate");
 pref("browser.gesture.swipe.up", "cmd_scrollTop");
@@ -948,16 +948,20 @@ pref("gecko.handlerService.allowRegister
 
 #ifdef MOZ_SAFE_BROWSING
 pref("browser.safebrowsing.enabled", true);
 pref("browser.safebrowsing.malware.enabled", true);
 pref("browser.safebrowsing.downloads.enabled", true);
 pref("browser.safebrowsing.downloads.remote.enabled", true);
 pref("browser.safebrowsing.downloads.remote.timeout_ms", 10000);
 pref("browser.safebrowsing.downloads.remote.url", "https://sb-ssl.google.com/safebrowsing/clientreport/download?key=%GOOGLE_API_KEY%");
+pref("browser.safebrowsing.downloads.remote.block_dangerous",            true);
+pref("browser.safebrowsing.downloads.remote.block_dangerous_host",       true);
+pref("browser.safebrowsing.downloads.remote.block_potentially_unwanted", false);
+pref("browser.safebrowsing.downloads.remote.block_uncommon",             false);
 pref("browser.safebrowsing.debug", false);
 
 pref("browser.safebrowsing.provider.google.lists", "goog-badbinurl-shavar,goog-downloadwhite-digest256,goog-phish-shavar,goog-malware-shavar,goog-unwanted-shavar");
 pref("browser.safebrowsing.provider.google.updateURL", "https://safebrowsing.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2&key=%GOOGLE_API_KEY%");
 pref("browser.safebrowsing.provider.google.gethashURL", "https://safebrowsing.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
 pref("browser.safebrowsing.provider.google.reportURL", "https://safebrowsing.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
 
 pref("browser.safebrowsing.reportPhishMistakeURL", "https://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%&url=");
@@ -1114,16 +1118,19 @@ pref("breakpad.reportURL", "https://cras
 
 // URL for "Learn More" for Crash Reporter
 pref("toolkit.crashreporter.infoURL",
      "https://www.mozilla.org/legal/privacy/firefox.html#crash-reporter");
 
 // base URL for web-based support pages
 pref("app.support.baseURL", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/");
 
+// a11y conflicts with e10s support page
+pref("app.support.e10sAccessibilityUrl", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/accessibility-ppt");
+
 // base url for web-based feedback pages
 #ifdef MOZ_DEV_EDITION
 pref("app.feedback.baseURL", "https://input.mozilla.org/%LOCALE%/feedback/firefoxdev/%VERSION%/");
 #else
 pref("app.feedback.baseURL", "https://input.mozilla.org/%LOCALE%/feedback/%APP%/%VERSION%/");
 #endif
 
 
@@ -1304,16 +1311,22 @@ pref("services.sync.prefs.sync.security.
 pref("services.sync.prefs.sync.security.OCSP.require", true);
 pref("services.sync.prefs.sync.security.default_personal_cert", true);
 pref("services.sync.prefs.sync.security.tls.version.min", true);
 pref("services.sync.prefs.sync.security.tls.version.max", true);
 pref("services.sync.prefs.sync.signon.rememberSignons", true);
 pref("services.sync.prefs.sync.spellchecker.dictionary", true);
 pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
 
+#ifdef NIGHTLY_BUILD
+pref("services.sync.syncedTabsUIRefresh", true);
+#else
+pref("services.sync.syncedTabsUIRefresh", false);
+#endif
+
 // Developer edition preferences
 #ifdef MOZ_DEV_EDITION
 sticky_pref("lightweightThemes.selectedThemeID", "firefox-devedition@mozilla.org");
 #else
 sticky_pref("lightweightThemes.selectedThemeID", "");
 #endif
 
 // Whether the character encoding menu is under the main Firefox button. This
@@ -1384,18 +1397,16 @@ pref("image.mem.max_decoded_image_kb", 2
 
 pref("social.sidebar.unload_timeout_ms", 10000);
 
 // Activation from inside of share panel is possible if activationPanelEnabled
 // is true. Pref'd off for release while usage testing is done through beta.
 pref("social.share.activationPanelEnabled", true);
 pref("social.shareDirectory", "https://activations.cdn.mozilla.net/sharePanel.html");
 
-pref("dom.identity.enabled", false);
-
 // Block insecure active content on https pages
 pref("security.mixed_content.block_active_content", true);
 
 // Show degraded UI for http pages with password fields.
 // Only for Nightly and Dev Edition for not, not for beta or release.
 #ifndef RELEASE_BUILD
 pref("security.insecure_password.ui.enabled", true);
 #else
@@ -1461,17 +1472,17 @@ pref("identity.fxaccounts.remote.force_a
 pref("identity.fxaccounts.remote.signin.uri", "https://accounts.firefox.com/signin?service=sync&context=fx_desktop_v3");
 
 // The remote content URL where FxAccountsWebChannel messages originate.
 pref("identity.fxaccounts.remote.webchannel.uri", "https://accounts.firefox.com/");
 
 // The URL we take the user to when they opt to "manage" their Firefox Account.
 // Note that this will always need to be in the same TLD as the
 // "identity.fxaccounts.remote.signup.uri" pref.
-pref("identity.fxaccounts.settings.uri", "https://accounts.firefox.com/settings");
+pref("identity.fxaccounts.settings.uri", "https://accounts.firefox.com/settings?service=sync&context=fx_desktop_v3");
 
 // The remote URL of the FxA Profile Server
 pref("identity.fxaccounts.remote.profile.uri", "https://profile.accounts.firefox.com/v1");
 
 // The remote URL of the FxA OAuth Server
 pref("identity.fxaccounts.remote.oauth.uri", "https://oauth.accounts.firefox.com/v1");
 
 // Whether we display profile images in the UI or not.
@@ -1532,18 +1543,16 @@ pref("browser.translation.neverForLangua
 // Show the translation UI bits, like the info bar, notification icon and preferences.
 pref("browser.translation.ui.show", false);
 // Allows to define the translation engine. Bing is default, Yandex may optionally switched on.
 pref("browser.translation.engine", "bing");
 
 // Telemetry settings.
 // Determines if Telemetry pings can be archived locally.
 pref("toolkit.telemetry.archive.enabled", true);
-// Whether we enable opt-out Telemetry for a sample of the release population.
-pref("toolkit.telemetry.optoutSample", true);
 
 // Telemetry experiments settings.
 pref("experiments.enabled", true);
 pref("experiments.manifest.fetchIntervalSeconds", 86400);
 pref("experiments.manifest.uri", "https://telemetry-experiment.cdn.mozilla.net/manifest/v1/firefox/%VERSION%/%CHANNEL%");
 // Whether experiments are supported by the current application profile.
 pref("experiments.supported", true);
 
@@ -1584,16 +1593,19 @@ pref("extensions.interposition.enabled",
 pref("extensions.interposition.prefetching", true);
 
 pref("browser.defaultbrowser.notificationbar", false);
 
 // How often to check for CPOW timeouts. CPOWs are only timed out by
 // the hang monitor.
 pref("dom.ipc.cpow.timeout", 500);
 
+// Causes access on unsafe CPOWs from browser code to throw by default.
+pref("dom.ipc.cpows.forbid-unsafe-from-browser", true);
+
 // Enable e10s hang monitoring (slow script checking and plugin hang
 // detection).
 pref("dom.ipc.processHangMonitor", true);
 
 #ifdef DEBUG
 // Don't report hangs in DEBUG builds. They're too slow and often a
 // debugger is attached.
 pref("dom.ipc.reportProcessHangs", false);
--- a/browser/base/content/aboutNetError.xhtml
+++ b/browser/base/content/aboutNetError.xhtml
@@ -139,22 +139,16 @@
 
         if (allowOverride) {
           document.getElementById("overrideWeakCryptoPanel").style.display = "flex";
           var overrideLink = document.getElementById("overrideWeakCrypto");
           overrideLink.addEventListener("click", () => doOverride(overrideLink), false);
         }
       }
 
-      function sendErrorReport() {
-        var event = new CustomEvent("AboutNetErrorSendReport", {bubbles:true});
-
-        document.dispatchEvent(event);
-      }
-
       function initPage()
       {
         var err = getErrorCode();
 
         // if it's an unknown error or there's no title or description
         // defined, get the generic message
         var errTitle = document.getElementById("et_" + err);
         var errDesc  = document.getElementById("ed_" + err);
@@ -255,23 +249,17 @@
                 // set the checkbox
                 checkbox.checked = true;
               }
 
               checkbox.addEventListener('change', function(evt) {
                   var event = new CustomEvent("AboutNetErrorSetAutomatic",
                     {bubbles:true, detail:evt.target.checked});
                   document.dispatchEvent(event);
-                  if (evt.target.checked) {
-                    sendErrorReport();
-                  }
                 }, false);
-
-              var retryBtn = document.getElementById('reportCertificateErrorRetry');
-              retryBtn.addEventListener('click', sendErrorReport, false);
             }
           }
           if (getErrorCode() == "weakCryptoUsed" || getErrorCode() == "sslv3Used") {
             showAdvancedButton(getErrorCode() == "weakCryptoUsed");
           }
         }.bind(this), true, true);
 
         var event = new CustomEvent("AboutNetErrorLoad", {bubbles:true});
@@ -522,22 +510,16 @@
       </script>
 
       <!-- UI for option to report certificate errors to Mozilla. Removed on
            init for other error types .-->
       <div id="certificateErrorReporting">
         <p>
           <input type="checkbox" id="automaticallyReportInFuture" />
           <label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic2;</label>
-
-          <span id="reportingState">
-            <button id="reportCertificateErrorRetry">&errorReporting.tryAgain;</button>
-            <span id="reportSendingMessage">&errorReporting.sending;</span>
-            <span id="reportSentMessage">&errorReporting.sent;</span>
-          </span>
         </p>
       </div>
 
       <div id="weakCryptoAdvancedPanel">
         <div id="weakCryptoAdvancedDescription">
           <p>&weakCryptoAdvanced.longDesc;</p>
         </div>
         <div id="advancedLongDesc" />
--- a/browser/base/content/aboutaccounts/aboutaccounts.js
+++ b/browser/base/content/aboutaccounts/aboutaccounts.js
@@ -22,21 +22,21 @@ const ACTION_URL_PARAM = "action";
 
 const OBSERVER_TOPICS = [
   fxAccountsCommon.ONVERIFIED_NOTIFICATION,
   fxAccountsCommon.ONLOGOUT_NOTIFICATION,
 ];
 
 function log(msg) {
   //dump("FXA: " + msg + "\n");
-};
+}
 
 function error(msg) {
   console.log("Firefox Account Error: " + msg + "\n");
-};
+}
 
 function getPreviousAccountNameHash() {
   try {
     return Services.prefs.getComplexValue(PREF_LAST_FXA_USER, Ci.nsISupportsString).data;
   } catch (_) {
     return "";
   }
 }
--- a/browser/base/content/aboutcerterror/aboutCertError.xhtml
+++ b/browser/base/content/aboutcerterror/aboutCertError.xhtml
@@ -91,23 +91,16 @@
         var checkbox = document.getElementById("automaticallyReportInFuture");
         checkbox.addEventListener("change", function ({target: {checked}}) {
           document.dispatchEvent(new CustomEvent("AboutCertErrorSetAutomatic", {
             detail: checked,
             bubbles: true
           }));
         });
 
-        var retryBtn = document.getElementById("reportCertificateErrorRetry");
-        retryBtn.addEventListener("click", function () {
-          document.dispatchEvent(new CustomEvent("AboutCertErrorSendReport", {
-            bubbles: true
-          }));
-        });
-
         addEventListener("AboutCertErrorOptions", function (event) {
           var options = JSON.parse(event.detail);
           if (options && options.enabled) {
             // Display error reporting UI
             document.getElementById("certificateErrorReporting").style.display = "block";
 
             // set the checkbox
             checkbox.checked = !!options.automatic;
@@ -282,22 +275,16 @@
         </div>
       </div>
 
       <!-- UI for option to report certificate errors to Mozilla. -->
       <div id="certificateErrorReporting">
         <p>
           <input type="checkbox" id="automaticallyReportInFuture" />
           <label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic;</label>
-
-          <span id="reportingState">
-            <button id="reportCertificateErrorRetry">&errorReporting.tryAgain;</button>
-            <span id="reportSendingMessage">&errorReporting.sending;</span>
-            <span id="reportSentMessage">&errorReporting.sent;</span>
-          </span>
         </p>
       </div>
 
       <!-- Advanced panel, which is hidden by default -->
       <div id="advancedPanel" style="visibility: hidden;">
         <p id="technicalContentText"/>
         <button id="exceptionDialogButton">&certerror.addException.label;</button>
       </div>
--- a/browser/base/content/abouthealthreport/abouthealth.js
+++ b/browser/base/content/abouthealthreport/abouthealth.js
@@ -7,38 +7,32 @@
 var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 const prefs = new Preferences("datareporting.healthreport.");
 
 const PREF_UNIFIED = "toolkit.telemetry.unified";
-const PREF_UNIFIED_OPTIN = "toolkit.telemetry.unifiedIsOptIn";
-
-// Whether v4 behavior is enabled, i.e. unified Telemetry features are on by default.
-const IS_V4 = Preferences.get(PREF_UNIFIED, false) &&
-              !Preferences.get(PREF_UNIFIED_OPTIN, false);
+const PREF_REPORTING_URL = "datareporting.healthreport.about.reportUrl";
 
 var healthReportWrapper = {
   init: function () {
     let iframe = document.getElementById("remote-report");
     iframe.addEventListener("load", healthReportWrapper.initRemotePage, false);
     iframe.src = this._getReportURI().spec;
     prefs.observe("uploadEnabled", this.updatePrefState, healthReportWrapper);
   },
 
   uninit: function () {
     prefs.ignore("uploadEnabled", this.updatePrefState, healthReportWrapper);
   },
 
   _getReportURI: function () {
-    const pref = IS_V4 ? "datareporting.healthreport.about.reportUrl"
-                       : "datareporting.healthreport.about.reportUrlUnified";
-    let url = Services.urlFormatter.formatURLPref(pref);
+    let url = Services.urlFormatter.formatURLPref(PREF_REPORTING_URL);
     return Services.io.newURI(url, null, null);
   },
 
   setDataSubmission: function (enabled) {
     MozSelfSupport.healthReportDataSubmissionEnabled = enabled;
     this.updatePrefState();
   },
 
--- a/browser/base/content/abouthome/aboutHome.xhtml
+++ b/browser/base/content/abouthome/aboutHome.xhtml
@@ -69,11 +69,12 @@
       <button class="launchButton" id="settings">&abouthome.preferencesButtonWin.label;</button>
 #else
       <button class="launchButton" id="settings">&abouthome.preferencesButtonUnix.label;</button>
 #endif
       <div id="restorePreviousSessionSeparator"/>
       <button class="launchButton" id="restorePreviousSession">&historyRestoreLastSession.label;</button>
     </div>
 
-    <a id="aboutMozilla" href="https://www.mozilla.org/about/?utm_source=about-home&amp;utm_medium=Referral"/>
+    <a id="aboutMozilla" href="https://www.mozilla.org/about/?utm_source=about-home&amp;utm_medium=Referral"
+       aria-label="&abouthome.aboutMozilla.label;"/>
   </body>
 </html>
--- a/browser/base/content/baseMenuOverlay.xul
+++ b/browser/base/content/baseMenuOverlay.xul
@@ -56,17 +56,17 @@
                   oncommand="openTourPage();"
                   label="&helpShowTour2.label;"
                   accesskey="&helpShowTour2.accesskey;"/>
         <menuitem id="menu_keyboardShortcuts"
                   oncommand="openHelpLink('keyboard-shortcuts')"
                   onclick="checkForMiddleClick(this, event);"
                   label="&helpKeyboardShortcuts.label;"
                   accesskey="&helpKeyboardShortcuts.accesskey;"/>
-#ifdef MOZ_SERVICES_HEALTHREPORT
+#ifdef MOZ_TELEMETRY_REPORTING
         <menuitem id="healthReport"
                   label="&healthReport2.label;"
                   accesskey="&healthReport2.accesskey;"
                   oncommand="openHealthReport()"
                   onclick="checkForMiddleClick(this, event);"/>
 #endif
         <menuitem id="troubleShooting"
                   accesskey="&helpTroubleshootingInfo.accesskey;"
--- a/browser/base/content/browser-eme.js
+++ b/browser/base/content/browser-eme.js
@@ -28,26 +28,16 @@ var gEMEHandler = {
     browser.reload();
   },
   getLearnMoreLink: function(msgId) {
     let text = gNavigatorBundle.getString("emeNotifications." + msgId + ".learnMoreLabel");
     let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
     return "<label class='text-link' href='" + baseURL + "drm-content'>" +
            text + "</label>";
   },
-  onDontAskAgain: function(menuPopupItem) {
-    let button = menuPopupItem.parentNode.anchorNode;
-    let bar = button.parentNode;
-    Services.prefs.setBoolPref("browser.eme.ui." + bar.value + ".disabled", true);
-    bar.close();
-  },
-  onNotNow: function(menuPopupItem) {
-    let button = menuPopupItem.parentNode.anchorNode;
-    button.parentNode.close();
-  },
   receiveMessage: function({target: browser, data: data}) {
     let parsedData;
     try {
       parsedData = JSON.parse(data);
     } catch (ex) {
       Cu.reportError("Malformed EME video message with data: " + data);
       return;
     }
@@ -100,33 +90,24 @@ var gEMEHandler = {
     this.showNotificationBar(browser, notificationId, keySystem, params, buttonCallback);
   },
   showNotificationBar: function(browser, notificationId, keySystem, labelParams, callback) {
     let box = gBrowser.getNotificationBox(browser);
     if (box.getNotificationWithValue(notificationId)) {
       return;
     }
 
-    // If the user turned these off, bail out:
-    try {
-      if (Services.prefs.getBoolPref("browser.eme.ui." + notificationId + ".disabled")) {
-        return;
-      }
-    } catch (ex) { /* Don't care if the pref doesn't exist */ }
-
     let msgPrefix = "emeNotifications." + notificationId + ".";
     let msgId = msgPrefix + "message";
 
-    // Specialcase Adobe's CDM on unsupported platforms to be more informative:
+    // Special-case Adobe's CDM message on unsupported platforms to be more informative:
     if (notificationId == "drmContentCDMNotSupported" &&
         keySystem.startsWith("com.adobe")) {
       let os = Services.appinfo.OS.toLowerCase();
-      if (os.startsWith("win") && Services.appinfo.XPCOMABI.startsWith("x86_64")) {
-        msgId = msgPrefix + "64bit.message";
-      } else if (os.startsWith("linux") || os.startsWith("darwin")) {
+      if (os.startsWith("linux") || os.startsWith("darwin")) {
         msgId = msgPrefix + "unsupportedOS.message";
         labelParams.splice(1, 0, os.startsWith("linux") ? "Linux" : "Mac OS X");
       }
     }
 
     let message = labelParams.length ?
                   gNavigatorBundle.getFormattedString(msgId, labelParams) :
                   gNavigatorBundle.getString(msgId);
@@ -135,23 +116,16 @@ var gEMEHandler = {
     if (callback) {
       let btnLabelId = msgPrefix + "button.label";
       let btnAccessKeyId = msgPrefix + "button.accesskey";
       buttons.push({
         label: gNavigatorBundle.getString(btnLabelId),
         accessKey: gNavigatorBundle.getString(btnAccessKeyId),
         callback: callback
       });
-
-      let optionsId = "emeNotifications.optionsButton";
-      buttons.push({
-        label: gNavigatorBundle.getString(optionsId + ".label"),
-        accessKey: gNavigatorBundle.getString(optionsId + ".accesskey"),
-        popup: "emeNotificationsPopup"
-      });
     }
 
     let iconURL = "chrome://browser/skin/drm-icon.svg#chains-black";
 
     // Do a little dance to get rich content into the notification:
     let fragment = document.createDocumentFragment();
     let descriptionContainer = document.createElement("description");
     descriptionContainer.innerHTML = message;
@@ -191,17 +165,16 @@ var gEMEHandler = {
     if (!Services.prefs.getPrefType(firstPlayPref) ||
         !Services.prefs.getBoolPref(firstPlayPref)) {
       document.getElementById(anchorId).setAttribute("firstplay", "true");
       Services.prefs.setBoolPref(firstPlayPref, true);
     } else {
       document.getElementById(anchorId).removeAttribute("firstplay");
     }
 
-
     let mainAction = {
       label: gNavigatorBundle.getString(btnLabelId),
       accessKey: gNavigatorBundle.getString(btnAccessKeyId),
       callback: function() { openPreferences("paneContent"); },
       dismiss: true
     };
     let options = {
       dismissed: true,
--- a/browser/base/content/browser-feeds.js
+++ b/browser/base/content/browser-feeds.js
@@ -44,18 +44,17 @@ var FeedHandler = {
     if (!feeds || feeds.length <= 1)
       return false;
 
     // Build the menu showing the available feed choices for viewing.
     let itemNodeType = isSubview ? "toolbarbutton" : "menuitem";
     for (let feedInfo of feeds) {
       let item = document.createElement(itemNodeType);
       let baseTitle = feedInfo.title || feedInfo.href;
-      let labelStr = gNavigatorBundle.getFormattedString("feedShowFeedNew", [baseTitle]);
-      item.setAttribute("label", labelStr);
+      item.setAttribute("label", baseTitle);
       item.setAttribute("feed", feedInfo.href);
       item.setAttribute("tooltiptext", feedInfo.href);
       item.setAttribute("crop", "center");
       let className = "feed-" + itemNodeType;
       if (isSubview) {
         className += " subviewbutton";
       }
       item.setAttribute("class", className);
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -106,60 +106,60 @@ var FullZoom = {
             break;
         }
         break;
     }
   },
 
   // nsIContentPrefObserver
 
-  onContentPrefSet: function FullZoom_onContentPrefSet(aGroup, aName, aValue) {
-    this._onContentPrefChanged(aGroup, aValue);
+  onContentPrefSet: function FullZoom_onContentPrefSet(aGroup, aName, aValue, aIsPrivate) {
+    this._onContentPrefChanged(aGroup, aValue, aIsPrivate);
   },
 
   onContentPrefRemoved: function FullZoom_onContentPrefRemoved(aGroup, aName) {
     this._onContentPrefChanged(aGroup, undefined);
   },
 
   /**
    * Appropriately updates the zoom level after a content preference has
    * changed.
    *
    * @param aGroup  The group of the changed preference.
    * @param aValue  The new value of the changed preference.  Pass undefined to
    *                indicate the preference's removal.
    */
-  _onContentPrefChanged: function FullZoom__onContentPrefChanged(aGroup, aValue) {
+  _onContentPrefChanged: function FullZoom__onContentPrefChanged(aGroup, aValue, aIsPrivate) {
     if (this._isNextContentPrefChangeInternal) {
       // Ignore changes that FullZoom itself makes.  This works because the
       // content pref service calls callbacks before notifying observers, and it
       // does both in the same turn of the event loop.
       delete this._isNextContentPrefChangeInternal;
       return;
     }
 
     let browser = gBrowser.selectedBrowser;
     if (!browser.currentURI)
       return;
 
+    let ctxt = this._loadContextFromBrowser(browser);
     let domain = this._cps2.extractDomain(browser.currentURI.spec);
     if (aGroup) {
-      if (aGroup == domain)
+      if (aGroup == domain && ctxt.usePrivateBrowsing == aIsPrivate)
         this._applyPrefToZoom(aValue, browser);
       return;
     }
 
     this._globalValue = aValue === undefined ? aValue :
                           this._ensureValid(aValue);
 
     // If the current page doesn't have a site-specific preference, then its
     // zoom should be set to the new global preference now that the global
     // preference has changed.
     let hasPref = false;
-    let ctxt = this._loadContextFromBrowser(browser);
     let token = this._getBrowserToken(browser);
     this._cps2.getByDomainAndName(browser.currentURI.spec, this.name, ctxt, {
       handleResult: function () { hasPref = true; },
       handleCompletion: function () {
         if (!hasPref && token.isCurrent)
           this._applyPrefToZoom(undefined, browser);
       }.bind(this)
     });
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -237,17 +237,19 @@
                   <menupopup id="viewSidebarMenu">
                     <menuitem id="menu_bookmarksSidebar"
                               key="viewBookmarksSidebarKb"
                               observes="viewBookmarksSidebar"/>
                     <menuitem id="menu_historySidebar"
                               key="key_gotoHistory"
                               observes="viewHistorySidebar"
                               label="&historyButton.label;"/>
-
+                    <menuitem id="menu_tabsSidebar"
+                              observes="viewTabsSidebar"
+                              label="&syncedTabs.sidebar.label;"/>
                     <!-- Service providers with sidebars are inserted between these two menuseperators -->
                     <menuseparator hidden="true"/>
                     <menuseparator class="social-provider-menu" hidden="true"/>
                   </menupopup>
                 </menu>
                 <menuseparator/>
                 <menu id="viewFullZoomMenu" label="&fullZoom.label;"
                       accesskey="&fullZoom.accesskey;"
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -347,17 +347,17 @@ var PlacesCommandHook = {
         // but open right into the "edit" state, start batching here, so
         // "Cancel" in that state removes the bookmark.
         StarUI.beginBatch();
       }
 
       var parent = aParent !== undefined ?
                    aParent : PlacesUtils.unfiledBookmarksFolderId;
       var descAnno = { name: PlacesUIUtils.DESCRIPTION_ANNO, value: description };
-      var txn = new PlacesCreateBookmarkTransaction(uri, parent, 
+      var txn = new PlacesCreateBookmarkTransaction(uri, parent,
                                                     PlacesUtils.bookmarks.DEFAULT_INDEX,
                                                     title, null, [descAnno]);
       PlacesUtils.transactionManager.doTransaction(txn);
       itemId = txn.item.id;
       // Set the character-set.
       if (charset && !PrivateBrowsingUtils.isBrowserPrivate(aBrowser))
         PlacesUtils.setCharsetForURI(uri, charset);
     }
@@ -409,17 +409,17 @@ var PlacesCommandHook = {
         info.title = docInfo.isErrorPage ?
           (yield PlacesUtils.promisePlaceInfo(aBrowser.currentURI)).title :
           aBrowser.contentTitle;
         info.title = info.title || url.href;
         description = docInfo.description;
         charset = aBrowser.characterSet;
       }
       catch (e) {
-      	Components.utils.reportError(e);
+        Components.utils.reportError(e);
       }
 
       if (aShowEditUI) {
         // If we bookmark the page here (i.e. page was not "starred" already)
         // but open right into the "edit" state, start batching here, so
         // "Cancel" in that state removes the bookmark.
         StarUI.beginBatch();
       }
@@ -428,17 +428,17 @@ var PlacesCommandHook = {
         info.annotations = [{ name: PlacesUIUtils.DESCRIPTION_ANNO
                             , value: description }];
       }
 
       info.guid = yield PlacesTransactions.NewBookmark(info).transact();
 
       // Set the character-set
       if (charset && !PrivateBrowsingUtils.isBrowserPrivate(aBrowser))
-      	 PlacesUtils.setCharsetForURI(makeURI(url.href), charset);
+         PlacesUtils.setCharsetForURI(makeURI(url.href), charset);
     }
 
     // Revert the contents of the location bar
     if (gURLBar)
       gURLBar.handleRevert();
 
     // If it was not requested to open directly in "edit" mode, we are done.
     if (!aShowEditUI)
@@ -473,17 +473,17 @@ var PlacesCommandHook = {
         resolve(msg.data);
       });
 
       mm.sendAsyncMessage("Bookmarks:GetPageDetails", { })
     });
   },
 
   /**
-   * Adds a bookmark to the page loaded in the current tab. 
+   * Adds a bookmark to the page loaded in the current tab.
    */
   bookmarkCurrentPage: function PCH_bookmarkCurrentPage(aShowEditUI, aParent) {
     this.bookmarkPage(gBrowser.selectedBrowser, aParent, aShowEditUI);
   },
 
   /**
    * Adds a bookmark to the page targeted by a link.
    * @param aParent
@@ -535,17 +535,17 @@ var PlacesCommandHook = {
         uniquePages[spec] = null;
         URIs.push(tab.linkedBrowser.currentURI);
       }
     });
     return URIs;
   },
 
   /**
-   * Adds a folder with bookmarks to all of the currently open tabs in this 
+   * Adds a folder with bookmarks to all of the currently open tabs in this
    * window.
    */
   bookmarkCurrentPages: function PCH_bookmarkCurrentPages() {
     let pages = this.uniqueCurrentPages;
     if (pages.length > 1) {
     PlacesUIUtils.showBookmarkDialog({ action: "add"
                                      , type: "folder"
                                      , URIList: pages
@@ -565,17 +565,17 @@ var PlacesCommandHook = {
 
     // Disable "Bookmark All Tabs" if there are less than two
     // "unique current pages".
     goSetCommandEnabled("Browser:BookmarkAllTabs",
                         this.uniqueCurrentPages.length >= 2);
   },
 
   /**
-   * Adds a Live Bookmark to a feed associated with the current page. 
+   * Adds a Live Bookmark to a feed associated with the current page.
    * @param     url
    *            The nsIURI of the page the feed was attached to
    * @title     title
    *            The title of the feed. Optional.
    * @subtitle  subtitle
    *            A short description of the feed. Optional.
    */
   addLiveBookmark: Task.async(function *(url, feedTitle, feedSubtitle) {
@@ -599,28 +599,28 @@ var PlacesCommandHook = {
                                      , defaultInsertionPoint: toolbarIP
                                      , hiddenRows: [ "feedLocation"
                                                    , "siteLocation"
                                                    , "description" ]
                                      }, window);
   }),
 
   /**
-   * Opens the Places Organizer. 
+   * Opens the Places Organizer.
    * @param   aLeftPaneRoot
    *          The query to select in the organizer window - options
    *          are: History, AllBookmarks, BookmarksMenu, BookmarksToolbar,
    *          UnfiledBookmarks, Tags and Downloads.
    */
   showPlacesOrganizer: function PCH_showPlacesOrganizer(aLeftPaneRoot) {
     var organizer = Services.wm.getMostRecentWindow("Places:Organizer");
     // Due to bug 528706, getMostRecentWindow can return closed windows.
     if (!organizer || organizer.closed) {
       // No currently open places window, so open one with the specified mode.
-      openDialog("chrome://browser/content/places/places.xul", 
+      openDialog("chrome://browser/content/places/places.xul",
                  "", "chrome,toolbar=yes,dialog=no,resizable", aLeftPaneRoot);
     }
     else {
       organizer.PlacesOrganizer.selectLeftPaneContainerByHierarchy(aLeftPaneRoot);
       organizer.focus();
     }
   }
 };
@@ -821,17 +821,17 @@ var BookmarksEventHandler = {
       this.onCommand(aEvent, aView);
     }
   },
 
   /**
    * Handler for command event for an item in the bookmarks toolbar.
    * Menus and submenus from the folder buttons bubble up to this handler.
    * Opens the item.
-   * @param aEvent 
+   * @param aEvent
    *        DOMEvent for the command
    * @param aView
    *        The places view which aEvent should be associated with.
    */
   onCommand: function BEH_onCommand(aEvent, aView) {
     var target = aEvent.originalTarget;
     if (target._placesNode)
       PlacesUIUtils.openNodeWithEvent(target._placesNode, aEvent, aView);
@@ -903,17 +903,17 @@ var PlacesMenuDNDHandler = {
   _closeDelayMs: 500,
   _loadTimer: null,
   _closeTimer: null,
   _closingTimerNode: null,
 
   /**
    * Called when the user enters the <menu> element during a drag.
    * @param   event
-   *          The DragEnter event that spawned the opening. 
+   *          The DragEnter event that spawned the opening.
    */
   onDragEnter: function PMDH_onDragEnter(event) {
     // Opening menus in a Places popup is handled by the view itself.
     if (!this._isStaticContainer(event.target))
       return;
 
     // If we re-enter the same menu or anchor before the close timer runs out,
     // we should ensure that we do not close:
@@ -974,49 +974,49 @@ var PlacesMenuDNDHandler = {
         popup.removeAttribute("autoopened");
         popup.hidePopup();
       }
     }, this._closeDelayMs, Ci.nsITimer.TYPE_ONE_SHOT);
   },
 
   /**
    * Determines if a XUL element represents a static container.
-   * @returns true if the element is a container element (menu or 
+   * @returns true if the element is a container element (menu or
    *`         menu-toolbarbutton), false otherwise.
    */
   _isStaticContainer: function PMDH__isContainer(node) {
     let isMenu = node.localName == "menu" ||
                  (node.localName == "toolbarbutton" &&
                   (node.getAttribute("type") == "menu" ||
                    node.getAttribute("type") == "menu-button"));
     let isStatic = !("_placesNode" in node) && node.lastChild &&
                    node.lastChild.hasAttribute("placespopup") &&
                    !node.parentNode.hasAttribute("placespopup");
     return isMenu && isStatic;
   },
 
   /**
    * Called when the user drags over the <menu> element.
    * @param   event
-   *          The DragOver event. 
+   *          The DragOver event.
    */
   onDragOver: function PMDH_onDragOver(event) {
     let ip = new InsertionPoint(PlacesUtils.bookmarksMenuFolderId,
                                 PlacesUtils.bookmarks.DEFAULT_INDEX,
                                 Components.interfaces.nsITreeView.DROP_ON);
     if (ip && PlacesControllerDragHelper.canDrop(ip, event.dataTransfer))
       event.preventDefault();
 
     event.stopPropagation();
   },
 
   /**
    * Called when the user drops on the <menu> element.
    * @param   event
-   *          The Drop event. 
+   *          The Drop event.
    */
   onDrop: function PMDH_onDrop(event) {
     // Put the item at the end of bookmark menu.
     let ip = new InsertionPoint(PlacesUtils.bookmarksMenuFolderId,
                                 PlacesUtils.bookmarks.DEFAULT_INDEX,
                                 Components.interfaces.nsITreeView.DROP_ON);
     PlacesControllerDragHelper.onDrop(ip, event.dataTransfer);
     PlacesControllerDragHelper.currentDropTarget = null;
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -183,16 +183,21 @@
         A 'syncstatus' attribute is set while actively syncing, and the label
         attribute which changes from "sync now" to "syncing" etc. -->
     <broadcaster id="sync-status"/>
     <!-- broadcasters of the "hidden" attribute to reflect setup state for
          menus -->
     <broadcaster id="sync-setup-state"/>
     <broadcaster id="sync-syncnow-state" hidden="true"/>
     <broadcaster id="sync-reauth-state" hidden="true"/>
+    <broadcaster id="viewTabsSidebar" autoCheck="false" sidebartitle="&syncedTabs.sidebar.label;"
+                 type="checkbox" group="sidebar"
+                 hidden="true"
+                 sidebarurl="chrome://browser/content/syncedtabs/sidebar.xhtml"
+                 oncommand="SidebarUI.toggle('viewTabsSidebar');"/>
     <broadcaster id="workOfflineMenuitemState"/>
     <broadcaster id="socialSidebarBroadcaster" hidden="true"/>
 
     <!-- DevTools broadcasters -->
     <broadcaster id="devtoolsMenuBroadcaster_DevToolbox"
                  label="&devToolboxMenuItem.label;"
                  type="checkbox" autocheck="false"
                  command="Tools:DevToolbox"
--- a/browser/base/content/browser-sidebar.js
+++ b/browser/base/content/browser-sidebar.js
@@ -186,17 +186,17 @@ var SidebarUI = {
    * @see SidebarUI note.
    *
    * @param {string} commandID ID of the xul:broadcaster element to use.
    */
   show(commandID) {
     return new Promise((resolve, reject) => {
       let sidebarBroadcaster = document.getElementById(commandID);
       if (!sidebarBroadcaster || sidebarBroadcaster.localName != "broadcaster") {
-        reject(new Error("Invalid sidebar broadcaster specified"));
+        reject(new Error("Invalid sidebar broadcaster specified: " + commandID));
         return;
       }
 
       let broadcasters = document.getElementsByAttribute("group", "sidebar");
       for (let broadcaster of broadcasters) {
         // skip elements that observe sidebar broadcasters and random
         // other elements
         if (broadcaster.localName != "broadcaster") {
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -365,17 +365,17 @@ SocialFlyout = {
     iframe.setAttribute("messagemanagergroup", "social");
     iframe.setAttribute("tooltip", "aHTMLTooltip");
     iframe.setAttribute("context", "contentAreaContextMenu");
     iframe.setAttribute("origin", SocialSidebar.provider.origin);
     panel.appendChild(iframe);
     // the xbl bindings for the iframe probably don't exist yet, so we can't
     // access iframe.messageManager directly - but can get at it with this dance.
     let mm = iframe.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader.messageManager;
-    mm.sendAsyncMessage("Social:SetErrorURL", null,
+    mm.sendAsyncMessage("Social:SetErrorURL",
                         { template: "about:socialerror?mode=compactInfo&origin=%{origin}" });
   },
 
   unload: function() {
     let panel = this.panel;
     panel.hidePopup();
     if (!panel.firstChild)
       return
@@ -507,17 +507,17 @@ SocialShare = {
     iframe.setAttribute("context", "contentAreaContextMenu");
     iframe.setAttribute("tooltip", "aHTMLTooltip");
     iframe.setAttribute("disableglobalhistory", "true");
     iframe.setAttribute("flex", "1");
     iframe.setAttribute("message", "true");
     iframe.setAttribute("messagemanagergroup", "social");
     panel.lastChild.appendChild(iframe);
     let mm = iframe.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader.messageManager;
-    mm.sendAsyncMessage("Social:SetErrorURL", null,
+    mm.sendAsyncMessage("Social:SetErrorURL",
                         { template: "about:socialerror?mode=compactInfo&origin=%{origin}&url=%{url}" });
 
     this.populateProviderMenu();
   },
 
   getSelectedProvider: function() {
     let provider;
     let lastProviderOrigin = this.iframe && this.iframe.getAttribute("origin");
@@ -634,27 +634,27 @@ SocialShare = {
         if (graphData) {
           // overwrite data retreived from page with data given to us as a param
           for (let p in graphData) {
             pageData[p] = graphData[p];
           }
         }
         this.sharePage(providerOrigin, pageData, target, anchor);
       });
-      gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetPageData");
+      gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetPageData", null, { target });
       return;
     }
-    // if this is a share of a selected item, get any microdata
-    if (!pageData.microdata && target) {
-      messageManager.addMessageListener("PageMetadata:MicrodataResult", _dataFn = (msg) => {
-        messageManager.removeMessageListener("PageMetadata:MicrodataResult", _dataFn);
-        pageData.microdata = msg.data;
+    // if this is a share of a selected item, get any microformats
+    if (!pageData.microformats && target) {
+      messageManager.addMessageListener("PageMetadata:MicroformatsResult", _dataFn = (msg) => {
+        messageManager.removeMessageListener("PageMetadata:MicroformatsResult", _dataFn);
+        pageData.microformats = msg.data;
         this.sharePage(providerOrigin, pageData, target, anchor);
       });
-      gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetMicrodata", null, { target });
+      gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetMicroformats", null, { target });
       return;
     }
     this.currentShare = pageData;
 
     let provider;
     if (providerOrigin)
       provider = Social._getProviderFromOrigin(providerOrigin);
     else
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -76,16 +76,22 @@ var gSyncUI = {
     this._obs.forEach(function(topic) {
       Services.obs.addObserver(this, topic, true);
     }, this);
 
     // initial label for the sync buttons.
     let broadcaster = document.getElementById("sync-status");
     broadcaster.setAttribute("label", this._stringBundle.GetStringFromName("syncnow.label"));
 
+    // Initialize the Synced Tabs Sidebar
+    if (Services.prefs.getBoolPref("services.sync.syncedTabsUIRefresh")) {
+      let sidebarBroadcaster = document.getElementById("viewTabsSidebar");
+      sidebarBroadcaster.removeAttribute("hidden");
+    }
+
     this.updateUI();
   },
 
 
   // Returns a promise that resolves with true if Sync needs to be configured,
   // false otherwise.
   _needsSetup() {
     // If Sync is configured for FxAccounts then we do that promise-dance.
@@ -357,17 +363,18 @@ var gSyncUI = {
     } else if (loginFailed) {
       // "need to reconnect/re-enter your password"
       tooltiptext = gFxAccounts.strings.formatStringFromName("reconnectDescription", [email], 1);
     } else {
       // Sync appears configured - format the "last synced at" time.
       try {
         let lastSync = new Date(Services.prefs.getCharPref("services.sync.lastSync"));
         // Show the day-of-week and time (HH:MM) of last sync
-        let lastSyncDateString = lastSync.toLocaleFormat("%a %H:%M");
+        let lastSyncDateString = lastSync.toLocaleDateString(undefined,
+          {weekday: 'long', hour: 'numeric', minute: 'numeric'});
         tooltiptext = this._stringBundle.formatStringFromName("lastSync2.label", [lastSyncDateString], 1);
       }
       catch (e) {
         // pref doesn't exist (which will be the case until we've seen the
         // first successful sync) or is invalid (which should be impossible!)
         // Just leave tooltiptext as the empty string in these cases, which
         // will cause the tooltip to be removed below.
       }
--- a/browser/base/content/browser-tabsintitlebar.js
+++ b/browser/base/content/browser-tabsintitlebar.js
@@ -207,31 +207,16 @@ var TabsInTitlebar = {
 
 
       // Finally, size the placeholders:
       if (AppConstants.platform == "macosx") {
         this._sizePlaceholder("fullscreen-button", secondaryButtonsWidth);
       }
       this._sizePlaceholder("caption-buttons", captionButtonsBoxWidth);
 
-      if (!this._draghandles) {
-        this._draghandles = {};
-        let tmp = {};
-        Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
-
-        let mouseDownCheck = function () {
-          return !this._dragBindingAlive && TabsInTitlebar.enabled;
-        };
-
-        this._draghandles.tabsToolbar = new tmp.WindowDraggingElement(tabsToolbar);
-        this._draghandles.tabsToolbar.mouseDownCheck = mouseDownCheck;
-
-        this._draghandles.navToolbox = new tmp.WindowDraggingElement(gNavToolbox);
-        this._draghandles.navToolbox.mouseDownCheck = mouseDownCheck;
-      }
     } else {
       document.documentElement.removeAttribute("tabsintitlebar");
       updateTitlebarDisplay();
 
       if (AppConstants.platform == "macosx") {
         let secondaryButtonsWidth = rect($("titlebar-secondary-buttonbox")).width;
         this._sizePlaceholder("fullscreen-button", secondaryButtonsWidth);
       }
--- a/browser/base/content/browser-trackingprotection.js
+++ b/browser/base/content/browser-trackingprotection.js
@@ -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/. */
 
 var TrackingProtection = {
   // If the user ignores the doorhanger, we stop showing it after some time.
-  MAX_INTROS: 0,
+  MAX_INTROS: 20,
   PREF_ENABLED_GLOBALLY: "privacy.trackingprotection.enabled",
   PREF_ENABLED_IN_PRIVATE_WINDOWS: "privacy.trackingprotection.pbmode.enabled",
   enabledGlobally: false,
   enabledInPrivateWindows: false,
   container: null,
   content: null,
   icon: null,
   activeTooltipText: null,
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -67,20 +67,16 @@ searchbar {
 toolbar[customizable="true"] {
   -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar");
 }
 
 %ifdef XP_MACOSX
 #toolbar-menubar {
   -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-menubar-stub");
 }
-
-toolbar[customizable="true"]:not([nowindowdrag="true"]) {
-  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag");
-}
 %endif
 
 #toolbar-menubar[autohide="true"] {
   -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-menubar-autohide");
 }
 
 #addon-bar {
   -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#addonbar-delegating");
@@ -117,16 +113,20 @@ panelview {
   transition: transform var(--panelui-subview-transition-duration);
 }
 
 panelview:not([mainview]):not([current]) {
   transition: visibility 0s linear var(--panelui-subview-transition-duration);
   visibility: collapse;
 }
 
+browser[frameType="social"][remote="true"] {
+  -moz-binding: url("chrome://global/content/bindings/remote-browser.xml#remote-browser");
+}
+
 tabbrowser {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser");
 }
 
 .tabbrowser-tabs {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tabs");
 }
 
@@ -222,20 +222,17 @@ toolbar[customizing] > .overflow-button 
 #main-window[inFullscreen] > #titlebar,
 #main-window[inFullscreen] .titlebar-placeholder,
 #main-window:not([tabsintitlebar]) .titlebar-placeholder {
   display: none;
 }
 
 #titlebar {
   -moz-binding: url("chrome://global/content/bindings/general.xml#windowdragbox");
-
-%ifdef XP_MACOSX
   -moz-window-dragging: drag;
-%endif
 }
 
 #titlebar-spacer {
   pointer-events: none;
 }
 
 #main-window[tabsintitlebar] #titlebar-buttonbox {
   position: relative;
@@ -292,16 +289,21 @@ toolbar[customizing] > .overflow-button 
   -moz-appearance: -moz-window-button-box-maximized;
 }
 
 #main-window[tabletmode] #titlebar-min,
 #main-window[tabletmode] #titlebar-max {
   display: none !important;
 }
 
+#main-window[tabsintitlebar] #TabsToolbar,
+#main-window[tabsintitlebar] #toolbar-menubar:not([autohide=true]),
+#main-window[tabsintitlebar] #navigator-toolbox > toolbar:not(#toolbar-menubar):-moz-lwtheme {
+  -moz-window-dragging: drag;
+}
 %endif
 
 %endif
 
 #main-window[inFullscreen][inDOMFullscreen] #navigator-toolbox,
 #main-window[inFullscreen][inDOMFullscreen] #fullscr-toggler,
 #main-window[inFullscreen][inDOMFullscreen] #sidebar-box,
 #main-window[inFullscreen][inDOMFullscreen] #sidebar-splitter,
@@ -354,16 +356,26 @@ toolbarpaletteitem > #personal-bookmarks
 }
 
 #nav-bar-customization-target > #personal-bookmarks,
 toolbar:not(#TabsToolbar) > #wrapper-personal-bookmarks,
 toolbar:not(#TabsToolbar) > #personal-bookmarks {
   -moz-box-flex: 1;
 }
 
+/* Ensure that empty parts of the bookmarks container can be dragged on OSX, and on other OSes
+ * only when a lwtheme is in use. */
+%ifdef XP_MACOSX
+#PlacesToolbarItems {
+%else
+#main-window[tabsintitlebar] #PlacesToolbarItems:-moz-lwtheme {
+%endif
+  -moz-window-dragging: drag;
+}
+
 #zoom-controls[cui-areatype="toolbar"]:not([overflowedItem=true]) > #zoom-reset-button > .toolbarbutton-text {
   display: -moz-box;
 }
 
 #urlbar-reload-button:not([displaystop]) + #urlbar-stop-button,
 #urlbar-reload-button[displaystop] {
   visibility: collapse;
 }
@@ -732,41 +744,32 @@ html|*#fullscreen-exit-button {
 .notification-anchor-icon {
   -moz-user-focus: normal;
 }
 
 .notification-anchor-icon:not([showing]) {
   display: none;
 }
 
-#notification-popup .text-link.custom-link {
-  -moz-binding: url("chrome://global/content/bindings/text.xml#text-label");
-  text-decoration: none;
-}
-
 #invalid-form-popup > description {
   max-width: 280px;
 }
 
 .form-validation-anchor {
   /* should occupy space but not be visible */
   opacity: 0;
   visibility: hidden;
   pointer-events: none;
   -moz-stack-sizing: ignore;
 }
 
 #addon-progress-notification {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#addon-progress-notification");
 }
 
-#identity-request-notification {
-  -moz-binding: url("chrome://browser/content/urlbarBindings.xml#identity-request-notification");
-}
-
 #click-to-play-plugins-notification {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#click-to-play-plugins-notification");
 }
 
 #login-fill-notification {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#login-fill-notification");
 }
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -848,24 +848,29 @@ function _loadURIWithFlags(browser, uri,
         uri: uri,
         flags: flags,
         referrer: referrer ? referrer.spec : null,
         referrerPolicy: referrerPolicy,
         postData: postData,
       });
     }
   } catch (e) {
-    // If anything goes wrong just switch remoteness manually and load the URI.
+    // If anything goes wrong when switching remoteness, just switch remoteness
+    // manually and load the URI.
     // We might lose history that way but at least the browser loaded a page.
     // This might be necessary if SessionStore wasn't initialized yet i.e.
     // when the homepage is a non-remote page.
-    Cu.reportError(e);
-    gBrowser.updateBrowserRemotenessByURL(browser, uri);
-    browser.webNavigation.loadURIWithOptions(uri, flags, referrer, referrerPolicy,
-                                             postData, null, null);
+    if (mustChangeProcess) {
+      Cu.reportError(e);
+      gBrowser.updateBrowserRemotenessByURL(browser, uri);
+      browser.webNavigation.loadURIWithOptions(uri, flags, referrer, referrerPolicy,
+                                               postData, null, null);
+    } else {
+      throw e;
+    }
   } finally {
     if (browser.userTypedClear) {
       browser.userTypedClear--;
     }
   }
 }
 
 // Starts a new load in the browser first switching the browser to the correct
@@ -2706,110 +2711,33 @@ var BrowserOnClick = {
       break;
       case "Browser:SSLErrorGoBack":
         goBackFromErrorPage();
       break;
     }
   },
 
   onSSLErrorReport: function(browser, documentURI, location, securityInfo) {
-    function showReportStatus(reportStatus) {
-      gBrowser.selectedBrowser
-          .messageManager
-          .sendAsyncMessage("Browser:SSLErrorReportStatus",
-                            {
-                              reportStatus: reportStatus,
-                              documentURI: documentURI
-                            });
-    }
-
     if (!Services.prefs.getBoolPref("security.ssl.errorReporting.enabled")) {
-      showReportStatus("error");
       Cu.reportError("User requested certificate error report sending, but certificate error reporting is disabled");
       return;
     }
 
-    let bin = TLS_ERROR_REPORT_TELEMETRY_MANUAL_SEND;
-    if (Services.prefs.getBoolPref("security.ssl.errorReporting.automatic")) {
-      bin = TLS_ERROR_REPORT_TELEMETRY_AUTO_SEND;
-    }
-    Services.telemetry.getHistogramById("TLS_ERROR_REPORT_UI").add(bin);
-
     let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
                            .getService(Ci.nsISerializationHelper);
     let transportSecurityInfo = serhelper.deserializeObject(securityInfo);
     transportSecurityInfo.QueryInterface(Ci.nsITransportSecurityInfo)
 
-    showReportStatus("activity");
-
-    /*
-     * Requested info for the report:
-     * - Domain of bad connection
-     * - Error type (e.g. Pinning, domain mismatch, etc)
-     * - Cert chain (at minimum, same data to distrust each cert in the
-     *   chain)
-     * - Request data (e.g. User Agent, IP, Timestamp)
-     *
-     * The request data should be added to the report by the receiving server.
-     */
-
-    // Convert the nsIX509CertList into a format that can be parsed into
-    // JSON
-    let asciiCertChain = [];
-
-    if (transportSecurityInfo.failedCertChain) {
-      let certs = transportSecurityInfo.failedCertChain.getEnumerator();
-      while (certs.hasMoreElements()) {
-        let cert = certs.getNext();
-        cert.QueryInterface(Ci.nsIX509Cert);
-        asciiCertChain.push(btoa(getDERString(cert)));
-      }
-    }
-
-    let report = {
-      hostname: location.hostname,
-      port: location.port,
-      timestamp: Math.round(Date.now() / 1000),
-      errorCode: transportSecurityInfo.errorCode,
-      failedCertChain: asciiCertChain,
-      userAgent: window.navigator.userAgent,
-      version: 1,
-      build: gAppInfo.appBuildID,
-      product: gAppInfo.name,
-      channel: UpdateUtils.UpdateChannel
-    }
-
-    let reportURL = Services.prefs.getCharPref("security.ssl.errorReporting.url");
-
-    let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
-        .createInstance(Ci.nsIXMLHttpRequest);
-    try {
-      xhr.open("POST", reportURL);
-    } catch (e) {
-      Cu.reportError("xhr.open exception", e);
-      showReportStatus("error");
-    }
-
-    xhr.onerror = function (e) {
-      // error making request to reportURL
-      Cu.reportError("xhr onerror", e);
-      showReportStatus("error");
-    };
-
-    xhr.onload = function (event) {
-      if (xhr.status !== 201 && xhr.status !== 0) {
-        // request returned non-success status
-        Cu.reportError("xhr returned failure code", xhr.status);
-        showReportStatus("error");
-      } else {
-        showReportStatus("complete");
-      }
-    };
-
-    xhr.send(JSON.stringify(report));
+    let errorReporter = Cc["@mozilla.org/securityreporter;1"]
+                          .getService(Ci.nsISecurityReporter);
+    // if location.port is the empty string, set to -1 (for consistency with
+    // port values from nsIURI)
+    let port = location.port === "" ? -1 : location.port;
+    errorReporter.reportTLSError(transportSecurityInfo,
+                                 location.hostname, port);
   },
 
   onAboutCertError: function (browser, elementId, isTopFrame, location, securityInfoAsString) {
     let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
 
     switch (elementId) {
       case "exceptionDialogButton":
         if (isTopFrame) {
@@ -3096,17 +3024,17 @@ function populateMirrorTabMenu(popup) {
   let services = CastingApps.getServicesForMirroring();
   services.forEach(service => {
     let item = doc.createElement("menuitem");
     item.setAttribute("label", service.friendlyName);
     item._service = service;
     item.addEventListener("command", mirrorMenuItemClicked);
     popup.appendChild(item);
   });
-};
+}
 
 function getWebNavigation()
 {
   return gBrowser.webNavigation;
 }
 
 function BrowserReloadWithFlags(reloadFlags) {
   let url = gBrowser.currentURI.spec;
@@ -5568,17 +5496,17 @@ function handleDroppedLink(event, url, n
     if (data.url &&
         lastLocationChange == gBrowser.selectedBrowser.lastLocationChange)
       loadURI(data.url, null, data.postData, false);
   });
 
   // Keep the event from being handled by the dragDrop listeners
   // built-in to gecko if they happen to be above us.
   event.preventDefault();
-};
+}
 
 function BrowserSetForcedCharacterSet(aCharset)
 {
   if (aCharset) {
     gBrowser.selectedBrowser.characterSet = aCharset;
     // Save the forced character-set
     if (!PrivateBrowsingUtils.isWindowPrivate(window))
       PlacesUtils.setCharsetForURI(getWebNavigation().currentURI, aCharset);
@@ -6493,17 +6421,21 @@ function isTabEmpty(aTab) {
 
   if (browser.canGoForward || browser.canGoBack)
     return false;
 
   return true;
 }
 
 function BrowserOpenSyncTabs() {
-  gSyncUI.openSyncedTabsPanel();
+  if (Services.prefs.getBoolPref("services.sync.syncedTabsUIRefresh")) {
+    gSyncUI.openSyncedTabsPanel();
+  } else {
+    switchToTabHavingURI("about:sync-tabs", true);
+  }
 }
 
 /**
  * Format a URL
  * eg:
  * echo formatURL("https://addons.mozilla.org/%LOCALE%/%APP%/%VERSION%/");
  * > https://addons.mozilla.org/en-US/firefox/3.0a1/
  *
@@ -7252,24 +7184,24 @@ var gIdentityHandler = {
   }
 };
 
 function getNotificationBox(aWindow) {
   var foundBrowser = gBrowser.getBrowserForDocument(aWindow.document);
   if (foundBrowser)
     return gBrowser.getNotificationBox(foundBrowser)
   return null;
-};
+}
 
 function getTabModalPromptBox(aWindow) {
   var foundBrowser = gBrowser.getBrowserForDocument(aWindow.document);
   if (foundBrowser)
     return gBrowser.getTabModalPromptBox(foundBrowser);
   return null;
-};
+}
 
 /* DEPRECATED */
 function getBrowser() {
   return gBrowser;
 }
 function getNavToolbox() {
   return gNavToolbox;
 }
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -459,25 +459,27 @@
       <vbox id="bookmarked-notification-dropmarker-anchor">
         <image id="bookmarked-notification-dropmarker-icon"/>
       </vbox>
     </hbox>
 
     <tooltip id="dynamic-shortcut-tooltip"
              onpopupshowing="UpdateDynamicShortcutTooltipText(this);"/>
 
-    <menupopup id="emeNotificationsPopup">
-      <menuitem id="emeNotificationsNotNow"
-                label="&emeNotificationsNotNow.label;"
-                acceskey="&emeNotificationsNotNow.accesskey;"
-                oncommand="gEMEHandler.onNotNow(this);"/>
-      <menuitem id="emeNotificationsDontAskAgain"
-                label="&emeNotificationsDontAskAgain.label;"
-                acceskey="&emeNotificationsDontAskAgain.accesskey;"
-                oncommand="gEMEHandler.onDontAskAgain(this);"/>
+    <menupopup id="SyncedTabsSidebarContext">
+      <menuitem label="&syncedTabs.context.openTab.label;"
+                accesskey="&syncedTabs.context.openTab.accesskey;"
+                id="syncedTabsOpenSelected"/>
+      <menuitem label="&syncedTabs.context.bookmarkSingleTab.label;"
+                accesskey="&syncedTabs.context.bookmarkSingleTab.accesskey;"
+                id="syncedTabsBookmarkSelected"/>
+      <menuseparator/>
+      <menuitem label="&syncedTabs.context.refreshList.label;"
+                accesskey="&syncedTabs.context.refreshList.accesskey;"
+                id="syncedTabsRefresh"/>
     </menupopup>
   </popupset>
 
 #ifdef CAN_DRAW_IN_TITLEBAR
 <vbox id="titlebar">
   <hbox id="titlebar-content">
     <spacer id="titlebar-spacer" flex="1"/>
     <hbox id="titlebar-buttonbox-container">
@@ -665,20 +667,16 @@
                      ontextentered="this.handleCommand(param);"
                      ontextreverted="return this.handleRevert();"
                      pageproxystate="invalid"
                      onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'"
                      onblur="setTimeout(() => { document.getElementById('identity-box').style.MozUserFocus = ''; }, 0);">
               <box id="notification-popup-box" hidden="true" align="center">
                 <image id="default-notification-icon" class="notification-anchor-icon" role="button"
                        aria-label="&urlbar.defaultNotificationAnchor.label;"/>
-                <!-- NB: the identity-notification-icon is used for persona-based auth and preffed
-                     off by default. It hasn't been updated for some time and liable to being
-                     removed.-->
-                <image id="identity-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="geo-notification-icon" class="notification-anchor-icon" role="button"
                        aria-label="&urlbar.geolocationNotificationAnchor.label;"/>
                 <image id="addons-notification-icon" class="notification-anchor-icon" role="button"
                        aria-label="&urlbar.addonsNotificationAnchor.label;"/>
                 <image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"
                        aria-label="&urlbar.indexedDBNotificationAnchor.label;"/>
                 <image id="login-fill-notification-icon" class="notification-anchor-icon" role="button"
                        aria-label="&urlbar.loginFillNotificationAnchor.label;"/>
@@ -809,40 +807,16 @@
             </menuitem>
             <!-- NB: temporary solution for bug 985024, this should go away soon. -->
             <menuitem id="BMB_bookmarksShowAllTop"
                       class="menuitem-iconic subviewbutton"
                       label="&showAllBookmarks2.label;"
                       command="Browser:ShowAllBookmarks"
                       key="manBookmarkKb"/>
             <menuseparator/>
-            <menuitem id="BMB_subscribeToPageMenuitem"
-#ifndef XP_MACOSX
-                      class="menuitem-iconic subviewbutton"
-#else
-                      class="subviewbutton"
-#endif
-                      label="&subscribeToPageMenuitem.label;"
-                      oncommand="return FeedHandler.subscribeToFeed(null, event);"
-                      onclick="checkForMiddleClick(this, event);"
-                      observes="singleFeedMenuitemState"/>
-            <menu id="BMB_subscribeToPageMenupopup"
-#ifndef XP_MACOSX
-                  class="menu-iconic subviewbutton"
-#else
-                  class="subviewbutton"
-#endif
-                  label="&subscribeToPageMenupopup.label;"
-                  observes="multipleFeedsMenuState">
-              <menupopup id="BMB_subscribeToPageSubmenuMenupopup"
-                         onpopupshowing="return FeedHandler.buildFeedList(event.target);"
-                         oncommand="return FeedHandler.subscribeToFeed(null, event);"
-                         onclick="checkForMiddleClick(this, event);"/>
-            </menu>
-            <menuseparator/>
             <menu id="BMB_bookmarksToolbar"
                   class="menu-iconic bookmark-item subviewbutton"
                   label="&personalbarCmd.label;"
                   container="true">
               <menupopup id="BMB_bookmarksToolbarPopup"
                          placespopup="true"
                          context="placesContext"
                          onpopupshowing="if (!this.parentNode._placesView)
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -125,17 +125,17 @@ var handleContentContextMenu = function 
   let contentType = null;
   let contentDisposition = null;
   if (event.target.nodeType == Ci.nsIDOMNode.ELEMENT_NODE &&
       event.target instanceof Ci.nsIImageLoadingContent &&
       event.target.currentURI) {
     disableSetDesktopBg = disableSetDesktopBackground(event.target);
 
     try {
-      let imageCache = 
+      let imageCache =
         Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
                                         .getImgCacheForDocument(doc);
       let props =
         imageCache.findEntryProperties(event.target.currentURI, doc);
       try {
         contentType = props.get("type", Ci.nsISupportsCString).data;
       } catch(e) {}
       try {
@@ -205,20 +205,18 @@ Cc["@mozilla.org/eventlistenerservice;1"
 const TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN = 0;
 const TLS_ERROR_REPORT_TELEMETRY_EXPANDED = 1;
 const TLS_ERROR_REPORT_TELEMETRY_SUCCESS  = 6;
 const TLS_ERROR_REPORT_TELEMETRY_FAILURE  = 7;
 
 var AboutCertErrorListener = {
   init(chromeGlobal) {
     addMessageListener("AboutCertErrorDetails", this);
-    addMessageListener("Browser:SSLErrorReportStatus", this);
     chromeGlobal.addEventListener("AboutCertErrorLoad", this, false, true);
     chromeGlobal.addEventListener("AboutCertErrorSetAutomatic", this, false, true);
-    chromeGlobal.addEventListener("AboutCertErrorSendReport", this, false, true);
   },
 
   get isAboutCertError() {
     return content.document.documentURI.startsWith("about:certerror");
   },
 
   handleEvent(event) {
     if (!this.isAboutCertError) {
@@ -227,134 +225,90 @@ var AboutCertErrorListener = {
 
     switch (event.type) {
       case "AboutCertErrorLoad":
         this.onLoad(event);
         break;
       case "AboutCertErrorSetAutomatic":
         this.onSetAutomatic(event);
         break;
-      case "AboutCertErrorSendReport":
-        this.onSendReport();
-        break;
     }
   },
 
   receiveMessage(msg) {
     if (!this.isAboutCertError) {
       return;
     }
 
     switch (msg.name) {
       case "AboutCertErrorDetails":
         this.onDetails(msg);
         break;
-      case "Browser:SSLErrorReportStatus":
-        this.onReportStatus(msg);
-        break;
     }
   },
 
   onLoad(event) {
     let originalTarget = event.originalTarget;
     let ownerDoc = originalTarget.ownerDocument;
     ClickEventHandler.onAboutCertError(originalTarget, ownerDoc);
 
+    // Set up the TLS Error Reporting UI - reports are sent automatically
+    // (from nsHttpChannel::OnStopRequest) if the user has previously enabled
+    // automatic sending of reports. The UI ensures that a report is sent
+    // for the certificate error currently displayed if the user enables it
+    // here.
     let automatic = Services.prefs.getBoolPref("security.ssl.errorReporting.automatic");
     content.dispatchEvent(new content.CustomEvent("AboutCertErrorOptions", {
       detail: JSON.stringify({
         enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
         automatic,
       })
     }));
-
-    if (automatic) {
-      this.onSendReport();
-    }
   },
 
   onDetails(msg) {
     let div = content.document.getElementById("certificateErrorText");
     div.textContent = msg.data.info;
   },
 
   onSetAutomatic(event) {
-    if (event.detail) {
-      this.onSendReport();
-    }
-
     sendAsyncMessage("Browser:SetSSLErrorReportAuto", {
       automatic: event.detail
     });
-  },
-
-  onSendReport() {
-    let doc = content.document;
-    let location = doc.location.href;
-
-    let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
-                     .getService(Ci.nsISerializationHelper);
-
-    let serializable =  docShell.failedChannel.securityInfo
-                                .QueryInterface(Ci.nsITransportSecurityInfo)
-                                .QueryInterface(Ci.nsISerializable);
 
-    let serializedSecurityInfo = serhelper.serializeToString(serializable);
+    // if we're enabling reports, send a report for this failure
+    if (event.detail) {
+      let doc = content.document;
+      let location = doc.location.href;
 
-    sendAsyncMessage("Browser:SendSSLErrorReport", {
-      documentURI: doc.documentURI,
-      location: {hostname: doc.location.hostname, port: doc.location.port},
-      securityInfo: serializedSecurityInfo
-    });
-  },
-
-  onReportStatus(msg) {
-    let doc = content.document;
-    if (doc.documentURI != msg.data.documentURI) {
-      return;
-    }
+      let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
+          .getService(Ci.nsISerializationHelper);
 
-    let reportSendingMsg = doc.getElementById("reportSendingMessage");
-    let reportSentMsg = doc.getElementById("reportSentMessage");
-    let retryBtn = doc.getElementById("reportCertificateErrorRetry");
+      let serializable =  docShell.failedChannel.securityInfo
+          .QueryInterface(Ci.nsITransportSecurityInfo)
+          .QueryInterface(Ci.nsISerializable);
+
+      let serializedSecurityInfo = serhelper.serializeToString(serializable);
 
-    switch (msg.data.reportStatus) {
-      case "activity":
-        // Hide the button that was just clicked
-        retryBtn.style.removeProperty("display");
-        reportSentMsg.style.removeProperty("display");
-        reportSendingMsg.style.display = "block";
-        break;
-      case "error":
-        // show the retry button
-        retryBtn.style.display = "block";
-        reportSendingMsg.style.removeProperty("display");
-        sendAsyncMessage("Browser:SSLErrorReportTelemetry",
-                         {reportStatus: TLS_ERROR_REPORT_TELEMETRY_FAILURE});
-        break;
-      case "complete":
-        // Show a success indicator
-        reportSentMsg.style.display = "block";
-        reportSendingMsg.style.removeProperty("display");
-        sendAsyncMessage("Browser:SSLErrorReportTelemetry",
-                         {reportStatus: TLS_ERROR_REPORT_TELEMETRY_SUCCESS});
-        break;
+      sendAsyncMessage("Browser:SendSSLErrorReport", {
+        documentURI: doc.documentURI,
+        location: {hostname: doc.location.hostname, port: doc.location.port},
+        securityInfo: serializedSecurityInfo
+      });
     }
-  }
+  },
 };
 
 AboutCertErrorListener.init(this);
 
 
 var AboutNetErrorListener = {
   init: function(chromeGlobal) {
     chromeGlobal.addEventListener('AboutNetErrorLoad', this, false, true);
     chromeGlobal.addEventListener('AboutNetErrorSetAutomatic', this, false, true);
-    chromeGlobal.addEventListener('AboutNetErrorSendReport', this, false, true);
-    chromeGlobal.addEventListener('AboutNetErrorUIExpanded', this, false, true);
     chromeGlobal.addEventListener('AboutNetErrorOverride', this, false, true);
   },
 
   get isAboutNetError() {
     return content.document.documentURI.startsWith("about:neterror");
   },
 
   handleEvent: function(aEvent) {
@@ -364,117 +318,65 @@ var AboutNetErrorListener = {
 
     switch (aEvent.type) {
     case "AboutNetErrorLoad":
       this.onPageLoad(aEvent);
       break;
     case "AboutNetErrorSetAutomatic":
       this.onSetAutomatic(aEvent);
       break;
-    case "AboutNetErrorSendReport":
-      this.onSendReport(aEvent);
-      break;
-    case "AboutNetErrorUIExpanded":
-      sendAsyncMessage("Browser:SSLErrorReportTelemetry",
-                       {reportStatus: TLS_ERROR_REPORT_TELEMETRY_EXPANDED});
-      break;
     case "AboutNetErrorOverride":
       this.onOverride(aEvent);
       break;
     }
   },
 
   onPageLoad: function(evt) {
     let automatic = Services.prefs.getBoolPref("security.ssl.errorReporting.automatic");
     content.dispatchEvent(new content.CustomEvent("AboutNetErrorOptions", {
-            detail: JSON.stringify({
-              enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
-            automatic: automatic
-            })
-          }
-    ));
+      detail: JSON.stringify({
+        enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
+        automatic: automatic
+      })
+    }));
 
     sendAsyncMessage("Browser:SSLErrorReportTelemetry",
                      {reportStatus: TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN});
-
-    if (automatic) {
-      this.onSendReport(evt);
-    }
-    // hide parts of the UI we don't need yet
-    let contentDoc = content.document;
-
-    let reportSendingMsg = contentDoc.getElementById("reportSendingMessage");
-    let reportSentMsg = contentDoc.getElementById("reportSentMessage");
-    let retryBtn = contentDoc.getElementById("reportCertificateErrorRetry");
-    reportSendingMsg.style.display = "none";
-    reportSentMsg.style.display = "none";
-    retryBtn.style.display = "none";
   },
 
   onSetAutomatic: function(evt) {
     sendAsyncMessage("Browser:SetSSLErrorReportAuto", {
-        automatic: evt.detail
-      });
-  },
-
-  onSendReport: function(evt) {
-    let contentDoc = content.document;
-
-    let reportSendingMsg = contentDoc.getElementById("reportSendingMessage");
-    let reportSentMsg = contentDoc.getElementById("reportSentMessage");
-    let retryBtn = contentDoc.getElementById("reportCertificateErrorRetry");
-
-    addMessageListener("Browser:SSLErrorReportStatus", function(message) {
-      // show and hide bits - but only if this is a message for the right
-      // document - we'll compare on document URI
-      if (contentDoc.documentURI === message.data.documentURI) {
-        switch(message.data.reportStatus) {
-        case "activity":
-          // Hide the button that was just clicked
-          retryBtn.style.display = "none";
-          reportSentMsg.style.display = "none";
-          reportSendingMsg.style.removeProperty("display");
-          break;
-        case "error":
-          // show the retry button
-          retryBtn.style.removeProperty("display");
-          reportSendingMsg.style.display = "none";
-          sendAsyncMessage("Browser:SSLErrorReportTelemetry",
-                           {reportStatus: TLS_ERROR_REPORT_TELEMETRY_FAILURE});
-          break;
-        case "complete":
-          // Show a success indicator
-          reportSentMsg.style.removeProperty("display");
-          reportSendingMsg.style.display = "none";
-          sendAsyncMessage("Browser:SSLErrorReportTelemetry",
-                           {reportStatus: TLS_ERROR_REPORT_TELEMETRY_SUCCESS});
-          break;
-        }
-      }
+      automatic: evt.detail
     });
 
-    let location = contentDoc.location.href;
+    // if we're enabling reports, send a report for this failure
+    if (evt.detail) {
+      let contentDoc = content.document;
+
+      let location = contentDoc.location.href;
 
-    let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
-                      .getService(Ci.nsISerializationHelper);
+      let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
+                        .getService(Ci.nsISerializationHelper);
 
-    let serializable = docShell.failedChannel.securityInfo
-                               .QueryInterface(Ci.nsITransportSecurityInfo)
-                               .QueryInterface(Ci.nsISerializable);
+      let serializable = docShell.failedChannel.securityInfo
+          .QueryInterface(Ci.nsITransportSecurityInfo)
+          .QueryInterface(Ci.nsISerializable);
 
-    let serializedSecurityInfo = serhelper.serializeToString(serializable);
+      let serializedSecurityInfo = serhelper.serializeToString(serializable);
 
-    sendAsyncMessage("Browser:SendSSLErrorReport", {
-      documentURI: contentDoc.documentURI,
-      location: {
-        hostname: contentDoc.location.hostname,
-        port: contentDoc.location.port
-      },
-      securityInfo: serializedSecurityInfo
-    });
+      sendAsyncMessage("Browser:SendSSLErrorReport", {
+        documentURI: contentDoc.documentURI,
+        location: {
+          hostname: contentDoc.location.hostname,
+          port: contentDoc.location.port
+        },
+        securityInfo: serializedSecurityInfo
+      });
+
+    }
   },
 
   onOverride: function(evt) {
     let contentDoc = content.document;
     let location = contentDoc.location;
 
     sendAsyncMessage("Browser:OverrideWeakCrypto", {
       documentURI: contentDoc.documentURI,
@@ -710,30 +612,30 @@ addEventListener("pageshow", function(ev
       persisted: event.persisted,
     });
   }
 });
 
 var PageMetadataMessenger = {
   init() {
     addMessageListener("PageMetadata:GetPageData", this);
-    addMessageListener("PageMetadata:GetMicrodata", this);
+    addMessageListener("PageMetadata:GetMicroformats", this);
   },
   receiveMessage(message) {
     switch(message.name) {
       case "PageMetadata:GetPageData": {
-        let result = PageMetadata.getData(content.document);
+        let target = message.objects.target;
+        let result = PageMetadata.getData(content.document, target);
         sendAsyncMessage("PageMetadata:PageDataResult", result);
         break;
       }
-
-      case "PageMetadata:GetMicrodata": {
+      case "PageMetadata:GetMicroformats": {
         let target = message.objects.target;
-        let result = PageMetadata.getMicrodata(content.document, target);
-        sendAsyncMessage("PageMetadata:MicrodataResult", result);
+        let result = PageMetadata.getMicroformats(content.document, target);
+        sendAsyncMessage("PageMetadata:MicroformatsResult", result);
         break;
       }
     }
   }
 }
 PageMetadataMessenger.init();
 
 addEventListener("ActivateSocialFeature", function (aEvent) {
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -1125,16 +1125,18 @@ nsContextMenu.prototype = {
                        Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
       openUILink(this.mediaURL, e, { disallowInheritPrincipal: true,
                                      referrerURI: referrerURI });
     }
   },
 
   saveVideoFrameAsImage: function () {
     let mm = this.browser.messageManager;
+    let isPrivate = PrivateBrowsingUtils.isBrowserPrivate(this.browser);
+
     let name = "";
     if (this.mediaURL) {
       try {
         let uri = makeURI(this.mediaURL);
         let url = uri.QueryInterface(Ci.nsIURL);
         if (url.fileBaseName)
           name = decodeURI(url.fileBaseName) + ".jpg";
       } catch (e) { }
@@ -1145,17 +1147,18 @@ nsContextMenu.prototype = {
     mm.sendAsyncMessage("ContextMenu:SaveVideoFrameAsImage", {}, {
       target: this.target,
     });
 
     let onMessage = (message) => {
       mm.removeMessageListener("ContextMenu:SaveVideoFrameAsImage:Result", onMessage);
       let dataURL = message.data.dataURL;
       saveImageURL(dataURL, name, "SaveImageTitle", true, false,
-                   document.documentURIObject, document);
+                   document.documentURIObject, null, null, null,
+                   isPrivate);
     };
     mm.addMessageListener("ContextMenu:SaveVideoFrameAsImage:Result", onMessage);
   },
 
   leaveDOMFullScreen: function() {
     document.mozCancelFullScreen();
   },
 
@@ -1381,28 +1384,30 @@ nsContextMenu.prototype = {
     if (this.onCanvas || this.onImage)
         this.saveMedia();
   },
 
   // Save URL of the clicked upon image, video, or audio.
   saveMedia: function() {
     let doc = this.ownerDoc;
     let referrerURI = gContextMenuContentData.documentURIObject;
+    let isPrivate = PrivateBrowsingUtils.isBrowserPrivate(this.browser);
     if (this.onCanvas) {
       // Bypass cache, since it's a data: URL.
       this._canvasToDataURL(this.target).then(function(dataURL) {
         saveImageURL(dataURL, "canvas.png", "SaveImageTitle",
-                     true, false, referrerURI, doc);
+                     true, false, referrerURI, null, null, null,
+                     isPrivate);
       }, Cu.reportError);
     }
     else if (this.onImage) {
       urlSecurityCheck(this.mediaURL, this.principal);
       saveImageURL(this.mediaURL, null, "SaveImageTitle", false,
-                   false, referrerURI, doc, gContextMenuContentData.contentType,
-                   gContextMenuContentData.contentDisposition);
+                   false, referrerURI, null, gContextMenuContentData.contentType,
+                   gContextMenuContentData.contentDisposition, isPrivate);
     }
     else if (this.onVideo || this.onAudio) {
       urlSecurityCheck(this.mediaURL, this.principal);
       var dialogTitle = this.onVideo ? "SaveVideoTitle" : "SaveAudioTitle";
       this.saveHelper(this.mediaURL, null, dialogTitle, false, doc, referrerURI,
                       this.frameOuterWindowID, "");
     }
   },
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -103,17 +103,17 @@ pageInfoTreeView.prototype = {
     var treecol = tree.columns.getNamedColumn(columnname);
 
     this.sortdir =
       gTreeUtils.sort(
         tree,
         this,
         this.data,
         treecol.index,
-        function textComparator(a, b) { return (a || "").toLowerCase().localeCompare((b || "").toLowerCase()); },
+        function textComparator(a, b) { return (a || "").toLowerCase().localeCompare((b || "").toLowerCase()); },
         this.sortcol,
         this.sortdir
       );
 
     Array.forEach(tree.columns, function(col) {
       col.element.removeAttribute("sortActive");
       col.element.removeAttribute("sortDirection");
     });
--- a/browser/base/content/pageinfo/security.js
+++ b/browser/base/content/pageinfo/security.js
@@ -122,17 +122,17 @@ var security = {
   mapIssuerOrganization: function(name) {
     if (!name) return null;
 
     if (name == "RSA Data Security, Inc.") return "Verisign, Inc.";
 
     // No mapping required
     return name;
   },
-  
+
   /**
    * Open the cookie manager window
    */
   viewCookies : function()
   {
     var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                        .getService(Components.interfaces.nsIWindowMediator);
     var win = wm.getMostRecentWindow("Browser:Cookies");
@@ -178,17 +178,17 @@ function securityOnLoad(uri, windowInfo)
   else {
     document.getElementById("securityTab").hidden = false;
   }
 
   const pageInfoBundle = document.getElementById("pageinfobundle");
 
   /* Set Identity section text */
   setText("security-identity-domain-value", info.hostName);
-  
+
   var owner, verifier;
   if (info.cert && !info.isBroken) {
     // Try to pull out meaningful values.  Technically these fields are optional
     // so we'll employ fallbacks where appropriate.  The EV spec states that Org
     // fields must be specified for subject and issuer so that case is simpler.
     if (info.isEV) {
       owner = info.cert.organization;
       verifier = security.mapIssuerOrganization(info.cAName);
@@ -226,28 +226,28 @@ function securityOnLoad(uri, windowInfo)
   /* Set Privacy & History section text */
   var yesStr = pageInfoBundle.getString("yes");
   var noStr = pageInfoBundle.getString("no");
 
   setText("security-privacy-cookies-value",
           hostHasCookies(uri) ? yesStr : noStr);
   setText("security-privacy-passwords-value",
           realmHasPasswords(uri) ? yesStr : noStr);
-  
+
   var visitCount = previousVisitCount(info.hostName);
   if(visitCount > 1) {
     setText("security-privacy-history-value",
             pageInfoBundle.getFormattedString("securityNVisits", [visitCount.toLocaleString()]));
   }
   else if (visitCount == 1) {
     setText("security-privacy-history-value",
             pageInfoBundle.getString("securityOneVisit"));
   }
   else {
-    setText("security-privacy-history-value", noStr);        
+    setText("security-privacy-history-value", noStr);
   }
 
   /* Set the Technical Detail section messages */
   const pkiBundle = document.getElementById("pkiBundle");
   var hdr;
   var msg1;
   var msg2;
 
@@ -278,17 +278,17 @@ function securityOnLoad(uri, windowInfo)
     if (info.hostName != null)
       msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_None1", [info.hostName]);
     else
       msg1 = pkiBundle.getString("pageInfo_Privacy_None3");
     msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
   }
   setText("security-technical-shortform", hdr);
   setText("security-technical-longform1", msg1);
-  setText("security-technical-longform2", msg2); 
+  setText("security-technical-longform2", msg2);
 }
 
 function setText(id, value)
 {
   var element = document.getElementById(id);
   if (!element)
     return;
   if (element.localName == "textbox" || element.localName == "label")
@@ -333,23 +333,23 @@ function realmHasPasswords(uri) {
 /**
  * Return the number of previous visits recorded for host before today.
  *
  * @param host - the domain name to look for in history
  */
 function previousVisitCount(host, endTimeReference) {
   if (!host)
     return false;
-  
+
   var historyService = Components.classes["@mozilla.org/browser/nav-history-service;1"]
                                  .getService(Components.interfaces.nsINavHistoryService);
-    
+
   var options = historyService.getNewQueryOptions();
   options.resultType = options.RESULTS_AS_VISIT;
-  
+
   // Search for visits to this host before today
   var query = historyService.getNewQuery();
   query.endTimeReference = query.TIME_RELATIVE_TODAY;
   query.endTime = 0;
   query.domain = host;
 
   var result = historyService.executeQuery(query, options);
   result.root.containerOpen = true;
--- a/browser/base/content/sanitize.js
+++ b/browser/base/content/sanitize.js
@@ -10,16 +10,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
                                   "resource://gre/modules/FormHistory.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
                                   "resource://gre/modules/Downloads.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
                                   "resource://gre/modules/Promise.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils",
+                                  "resource://gre/modules/PromiseUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
                                   "resource:///modules/DownloadsCommon.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
                                   "resource://gre/modules/TelemetryStopwatch.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "console",
                                   "resource://gre/modules/Console.jsm");
@@ -334,16 +336,23 @@ Sanitizer.prototype = {
         var windows = windowManager.getEnumerator("navigator:browser");
         while (windows.hasMoreElements()) {
           let currentWindow = windows.getNext();
           let currentDocument = currentWindow.document;
           let searchBar = currentDocument.getElementById("searchbar");
           if (searchBar)
             searchBar.textbox.reset();
           let tabBrowser = currentWindow.gBrowser;
+          if (!tabBrowser) {
+            // No tab browser? This means that it's too early during startup (typically,
+            // Session Restore hasn't completed yet). Since we don't have find
+            // bars at that stage and since Session Restore will not restore
+            // find bars further down during startup, we have nothing to clear.
+            continue;
+          }
           for (let tab of tabBrowser.tabs) {
             if (tabBrowser.isFindBarInitialized(tab))
               tabBrowser.getFindBar(tab).clear();
           }
           // Clear any saved find value
           tabBrowser._lastFindValue = "";
         }
 
@@ -678,37 +687,34 @@ Sanitizer.showUI = function(aParentWindo
  * sanitize UI, according to user preferences
  */
 Sanitizer.sanitize = function(aParentWindow)
 {
   Sanitizer.showUI(aParentWindow);
 };
 
 Sanitizer.onStartup = Task.async(function*() {
-  // Make sure that we are triggered during shutdown, at the right time.
-  let shutdownClient = Cc["@mozilla.org/browser/nav-history-service;1"]
-     .getService(Ci.nsPIPlacesDatabase)
+  // Make sure that we are triggered during shutdown, at the right time,
+  // and only once.
+  let placesClient = Cc["@mozilla.org/browser/nav-history-service;1"]     .getService(Ci.nsPIPlacesDatabase)
      .shutdownClient
      .jsclient;
 
-  shutdownClient.addBlocker("sanitize.js: Sanitize on shutdown",
-    () => Sanitizer.onShutdown());
-
-    // One time migration to remove support for the clear saved passwords on exit feature.
-    if (!Services.prefs.getBoolPref("privacy.sanitize.migrateClearSavedPwdsOnExit")) {
-      let deprecatedPref = "privacy.clearOnShutdown.passwords";
-      let doUpdate = Services.prefs.prefHasUserValue(deprecatedPref) &&
-                     Services.prefs.getBoolPref(deprecatedPref);
-      if (doUpdate) {
-        Services.logins.removeAllLogins();
-        Services.prefs.setBoolPref("signon.rememberSignons", false);
-      }
-      Services.prefs.clearUserPref(deprecatedPref);
-      Services.prefs.setBoolPref("privacy.sanitize.migrateClearSavedPwdsOnExit", true);
+  let deferredSanitization = PromiseUtils.defer();
+  let sanitizationInProgress = false;
+  let doSanitize = function() {
+    if (sanitizationInProgress) {
+      return deferredSanitization.promise;
+    }
+    sanitizationInProgress = true;
+    Sanitizer.onShutdown().catch(er => {Promise.reject(er) /* Do not return rejected promise */;}).then(() =>
+      deferredSanitization.resolve()
+    );
   }
+  placesClient.addBlocker("sanitize.js: Sanitize on shutdown", doSanitize);
 
   // Handle incomplete sanitizations
   if (Preferences.has(Sanitizer.PREF_SANITIZE_IN_PROGRESS)) {
     // Firefox crashed during sanitization.
     let s = new Sanitizer();
     let json = Preferences.get(Sanitizer.PREF_SANITIZE_IN_PROGRESS);
     let itemsToClear = JSON.parse(json);
     yield s.sanitize(itemsToClear);
--- a/browser/base/content/social-content.js
+++ b/browser/base/content/social-content.js
@@ -9,42 +9,171 @@
 var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 // social frames are always treated as app tabs
 docShell.isAppTab = true;
 
+var gDOMContentLoaded = false;
+addEventListener("DOMContentLoaded", function() {
+  gDOMContentLoaded = true;
+  sendAsyncMessage("DOMContentLoaded");
+});
+var gDOMTitleChangedByUs = false;
+addEventListener("DOMTitleChanged", function(e) {
+  if (!gDOMTitleChangedByUs) {
+    sendAsyncMessage("DOMTitleChanged", {
+      title: e.target.title
+    });
+    gDOMTitleChangedByUs = false;
+  }
+});
+
 // Error handling class used to listen for network errors in the social frames
 // and replace them with a social-specific error page
 SocialErrorListener = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMEventListener,
+                                         Ci.nsIWebProgressListener,
                                          Ci.nsISupportsWeakReference,
                                          Ci.nsISupports]),
 
   defaultTemplate: "about:socialerror?mode=tryAgainOnly&url=%{url}&origin=%{origin}",
   urlTemplate: null,
 
   init() {
+    addMessageListener("Loop:MonitorPeerConnectionLifecycle", this);
+    addMessageListener("Loop:GetAllWebrtcStats", this);
+    addMessageListener("Social:CustomEvent", this);
+    addMessageListener("Social:EnsureFocus", this);
+    addMessageListener("Social:EnsureFocusElement", this);
+    addMessageListener("Social:HookWindowCloseForPanelClose", this);
+    addMessageListener("Social:ListenForEvents", this);
+    addMessageListener("Social:SetDocumentTitle", this);
     addMessageListener("Social:SetErrorURL", this);
+    addMessageListener("Social:WaitForDocumentVisible", this);
+    addMessageListener("WaitForDOMContentLoaded", this);
     let webProgress = docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                               .getInterface(Components.interfaces.nsIWebProgress);
     webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_REQUEST |
                                           Ci.nsIWebProgress.NOTIFY_LOCATION);
   },
+
   receiveMessage(message) {
-    switch(message.name) {
-      case "Social:SetErrorURL": {
-        // either a url or null to reset to default template
-        this.urlTemplate = message.objects.template;
-      }
+    let document = content.document;
+
+    switch (message.name) {
+      case "Loop:GetAllWebrtcStats":
+        content.WebrtcGlobalInformation.getAllStats(allStats => {
+          content.WebrtcGlobalInformation.getLogging("", logs => {
+            sendAsyncMessage("Loop:GetAllWebrtcStats", {
+              allStats: allStats,
+              logs: logs
+            });
+          });
+        }, message.data.peerConnectionID);
+        break;
+      case "Loop:MonitorPeerConnectionLifecycle":
+        let ourID = content.QueryInterface(Ci.nsIInterfaceRequestor)
+          .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
+
+        let onPCLifecycleChange = (pc, winID, type) => {
+          if (winID != ourID) {
+            return;
+          }
+
+          sendAsyncMessage("Loop:PeerConnectionLifecycleChange", {
+            iceConnectionState: pc.iceConnectionState,
+            locationHash: content.location.hash,
+            peerConnectionID: pc.id,
+            type: type
+          });
+        };
+
+        let pc_static = new content.RTCPeerConnectionStatic();
+        pc_static.registerPeerConnectionLifecycleCallback(onPCLifecycleChange);
+        break;
+      case "Social:CustomEvent":
+        let ev = new content.CustomEvent(message.data.name, message.data.detail ?
+          { detail: message.data.detail } : null);
+        content.dispatchEvent(ev);
+        break;
+      case "Social:EnsureFocus":
+        Services.focus.focusedWindow = content;
+        sendAsyncMessage("Social:FocusEnsured");
+        break;
+      case "Social:EnsureFocusElement":
+        let fm = Services.focus;
+        fm.moveFocus(document.defaultView, null, fm.MOVEFOCUS_FIRST, fm.FLAG_NOSCROLL);
+        sendAsyncMessage("Social:FocusEnsured");
+        break;
+      case "Social:HookWindowCloseForPanelClose":
+        // We allow window.close() to close the panel, so add an event handler for
+        // this, then cancel the event (so the window itself doesn't die) and
+        // close the panel instead.
+        // However, this is typically affected by the dom.allow_scripts_to_close_windows
+        // preference, but we can avoid that check by setting a flag on the window.
+        let dwu = content.QueryInterface(Ci.nsIInterfaceRequestor)
+           .getInterface(Ci.nsIDOMWindowUtils);
+        dwu.allowScriptsToClose();
+
+        content.addEventListener("DOMWindowClose", function _mozSocialDOMWindowClose(evt) {
+          sendAsyncMessage("DOMWindowClose");
+          // preventDefault stops the default window.close() function being called,
+          // which doesn't actually close anything but causes things to get into
+          // a bad state (an internal 'closed' flag is set and debug builds start
+          // asserting as the window is used.).
+          // None of the windows we inject this API into are suitable for this
+          // default close behaviour, so even if we took no action above, we avoid
+          // the default close from doing anything.
+          evt.preventDefault();
+        }, true);
+        break;
+      case "Social:ListenForEvents":
+        for (let eventName of message.data.eventNames) {
+          content.addEventListener(eventName, this);
+        }
+        break;
+      case "Social:SetDocumentTitle":
+        let title = message.data.title;
+        if (title && (title = title.trim())) {
+          gDOMTitleChangedByUs = true;
+          document.title = title;
+        }
+        break;
+      case "Social:SetErrorURL":
+        // Either a url or null to reset to default template.
+        this.urlTemplate = message.data.template;
+        break;
+      case "Social:WaitForDocumentVisible":
+        if (!document.hidden) {
+          sendAsyncMessage("Social:DocumentVisible");
+          break;
+        }
+
+        document.addEventListener("visibilitychange", function onVisibilityChanged() {
+          document.removeEventListener("visibilitychange", onVisibilityChanged);
+          sendAsyncMessage("Social:DocumentVisible");
+        });
+        break;
+      case "WaitForDOMContentLoaded":
+        if (gDOMContentLoaded) {
+          sendAsyncMessage("DOMContentLoaded");
+        }
+        break;
     }
   },
 
+  handleEvent: function(event) {
+    sendAsyncMessage("Social:CustomEvent", {
+      name: event.type
+    });
+  },
+
   setErrorPage() {
     // if this is about:providerdirectory, use the directory iframe
     let frame = docShell.chromeEventHandler;
     let origin = frame.getAttribute("origin");
     let src = frame.getAttribute("src");
     if (src == "about:providerdirectory") {
       frame = content.document.getElementById("activation-frame");
       src = frame.getAttribute("src");
--- a/browser/base/content/socialchat.xml
+++ b/browser/base/content/socialchat.xml
@@ -5,111 +5,121 @@
     xmlns:xbl="http://www.mozilla.org/xbl"
     xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <binding id="chatbox">
     <content orient="vertical" mousethrough="never">
       <xul:hbox class="chat-titlebar" xbl:inherits="minimized,selected,activity" align="baseline">
         <xul:hbox flex="1" onclick="document.getBindingParent(this).onTitlebarClick(event);">
           <xul:image class="chat-status-icon" xbl:inherits="src=image"/>
-          <xul:label class="chat-title" flex="1" xbl:inherits="value=label" crop="center"/>
+          <xul:label class="chat-title" flex="1" xbl:inherits="crop=titlecrop,value=label" crop="end"/>
         </xul:hbox>
         <xul:toolbarbutton anonid="webRTC-shareScreen-icon"
                            class="notification-anchor-icon chat-toolbarbutton"
                            oncommand="document.getBindingParent(this).showNotifications(this); event.stopPropagation();"/>
         <xul:toolbarbutton anonid="webRTC-sharingScreen-icon"
                            class="notification-anchor-icon chat-toolbarbutton"
                            oncommand="document.getBindingParent(this).showNotifications(this); event.stopPropagation();"/>
         <xul:toolbarbutton anonid="notification-icon" class="notification-anchor-icon chat-toolbarbutton"
                            oncommand="document.getBindingParent(this).showNotifications(this); event.stopPropagation();"/>
         <xul:toolbarbutton anonid="minimize" class="chat-minimize-button chat-toolbarbutton"
                            oncommand="document.getBindingParent(this).toggle();"/>
         <xul:toolbarbutton anonid="swap" class="chat-swap-button chat-toolbarbutton"
                            oncommand="document.getBindingParent(this).swapWindows();"/>
         <xul:toolbarbutton anonid="close" class="chat-close-button chat-toolbarbutton"
                            oncommand="document.getBindingParent(this).close();"/>
       </xul:hbox>
+      <xul:browser anonid="remote-content" class="chat-frame" flex="1"
+                   context="contentAreaContextMenu"
+                   disableglobalhistory="true"
+                   frameType="social"
+                   message="true"
+                   messagemanagergroup="social"
+                   tooltip="aHTMLTooltip"
+                   remote="true"
+                   xbl:inherits="src,origin"
+                   type="content"/>
+
       <xul:browser anonid="content" class="chat-frame" flex="1"
-                  context="contentAreaContextMenu"
-                  disableglobalhistory="true"
-                  message="true"
-                  messagemanagergroup="social"
-                  tooltip="aHTMLTooltip"
-                  xbl:inherits="src,origin" type="content"/>
+                   context="contentAreaContextMenu"
+                   disableglobalhistory="true"
+                   message="true"
+                   messagemanagergroup="social"
+                   tooltip="aHTMLTooltip"
+                   xbl:inherits="src,origin"
+                   type="content"/>
     </content>
 
-    <implementation implements="nsIDOMEventListener">
+    <implementation implements="nsIDOMEventListener, nsIMessageListener">
       <constructor><![CDATA[
         const kAnchorMap = new Map([
           ["", "notification-"],
           ["webRTC-shareScreen-", ""],
           ["webRTC-sharingScreen-", ""]
         ]);
-        for (let [getterPrefix, idPrefix] of kAnchorMap) {
-          let getter = getterPrefix + "popupnotificationanchor";
-          let anonid = (idPrefix || getterPrefix) + "icon";
-          this.content.__defineGetter__(getter, () => {
-            delete this.content[getter];
-            return this.content[getter] = document.getAnonymousElementByAttribute(
-              this, "anonid", anonid);
-          });
+        const kBrowsers = [
+          document.getAnonymousElementByAttribute(this, "anonid", "content"),
+          document.getAnonymousElementByAttribute(this, "anonid", "remote-content")
+        ];
+        for (let content of kBrowsers) {
+          for (let [getterPrefix, idPrefix] of kAnchorMap) {
+            let getter = getterPrefix + "popupnotificationanchor";
+            let anonid = (idPrefix || getterPrefix) + "icon";
+            content.__defineGetter__(getter, () => {
+              delete content[getter];
+              return content[getter] = document.getAnonymousElementByAttribute(
+                this, "anonid", anonid);
+            });
+          }
         }
 
-        let contentWindow = this.contentWindow;
+        let mm = this.content.messageManager;
         // process this._callbacks, then set to null so the chatbox creator
         // knows to make new callbacks immediately.
         if (this._callbacks) {
           for (let callback of this._callbacks) {
             callback(this);
           }
           this._callbacks = null;
         }
-        this.addEventListener("DOMContentLoaded", function DOMContentLoaded(event) {
-          if (event.target != this.contentDocument)
-            return;
-          this.removeEventListener("DOMContentLoaded", DOMContentLoaded, true);
+
+        mm.addMessageListener("DOMTitleChanged", this);
+
+        mm.sendAsyncMessage("WaitForDOMContentLoaded");
+        mm.addMessageListener("DOMContentLoaded", function DOMContentLoaded(event) {
+          mm.removeMessageListener("DOMContentLoaded", DOMContentLoaded);
           this.isActive = !this.minimized;
           this._chat.loadButtonSet(this, this.getAttribute("buttonSet"));
           this._deferredChatLoaded.resolve(this);
-        }, true);
+        }.bind(this));
 
-        if (this.src)
-          this.setAttribute("src", this.src);
+        this.setActiveBrowser();
       ]]></constructor>
 
       <field name="_deferredChatLoaded" readonly="true">
         Promise.defer();
       </field>
 
       <property name="promiseChatLoaded">
         <getter>
           return this._deferredChatLoaded.promise;
         </getter>
       </property>
 
-      <field name="content" readonly="true">
-        document.getAnonymousElementByAttribute(this, "anonid", "content");
-      </field>
+      <property name="content">
+        <getter>
+          return document.getAnonymousElementByAttribute(this, "anonid",
+            (this.remote ? "remote-" : "") + "content");
+        </getter>
+      </property>
 
       <field name="_chat" readonly="true">
         Cu.import("resource:///modules/Chat.jsm", {}).Chat;
       </field>
 
-      <property name="contentWindow">
-        <getter>
-          return this.content.contentWindow;
-        </getter>
-      </property>
-
-      <property name="contentDocument">
-        <getter>
-          return this.content.contentDocument;
-        </getter>
-      </property>
-
       <property name="minimized">
         <getter>
           return this.getAttribute("minimized") == "true";
         </getter>
         <setter><![CDATA[
           // Note that this.isActive is set via our transitionend handler so
           // the content doesn't see intermediate values.
           let parent = this.chatbar;
@@ -138,39 +148,70 @@
       <property name="isActive">
         <getter>
           return this.content.docShellIsActive;
         </getter>
         <setter>
           this.content.docShellIsActive = !!val;
 
           // let the chat frame know if it is being shown or hidden
-          let evt = this.contentDocument.createEvent("CustomEvent");
-          evt.initCustomEvent(val ? "socialFrameShow" : "socialFrameHide", true, true, {});
-          this.contentDocument.documentElement.dispatchEvent(evt);
+          this.content.messageManager.sendAsyncMessage("Social:CustomEvent", {
+            name: val ? "socialFrameShow" : "socialFrameHide"
+          });
         </setter>
       </property>
 
+      <field name="_remote">false</field>
+      <property name="remote" onget="return this._remote;">
+        <setter><![CDATA[
+          this._remote = !!val;
+
+          this.setActiveBrowser();
+        ]]></setter>
+      </property>
+
+      <method name="setActiveBrowser">
+        <body><![CDATA[
+          // Make sure we only show one browser element at a time.
+          let content = document.getAnonymousElementByAttribute(this, "anonid", "content");
+          let remoteContent = document.getAnonymousElementByAttribute(this, "anonid", "remote-content");
+          remoteContent.setAttribute("hidden", !this.remote);
+          content.setAttribute("hidden", this.remote);
+          remoteContent.removeAttribute("src");
+          content.removeAttribute("src");
+
+          if (this.src) {
+            this.setAttribute("src", this.src);
+
+            // Stop loading of the document - that is set before this method was
+            // called - in the now hidden browser.
+            (this.remote ? content : remoteContent).setAttribute("src", "about:blank");
+          }
+        ]]></body>
+      </method>
+
       <method name="showNotifications">
         <parameter name="aAnchor"/>
         <body><![CDATA[
         PopupNotifications._reshowNotifications(aAnchor,
                                                 this.content);
         ]]></body>
       </method>
 
       <method name="swapDocShells">
         <parameter name="aTarget"/>
         <body><![CDATA[
-          aTarget.setAttribute("label", this.contentDocument.title);
+          aTarget.setAttribute("label", this.content.contentTitle);
 
+          aTarget.remote = this.remote;
           aTarget.src = this.src;
-          aTarget.content.setAttribute("origin", this.content.getAttribute("origin"));
-          aTarget.content.popupnotificationanchor.className = this.content.popupnotificationanchor.className;
-          aTarget.content.swapDocShells(this.content);
+          let content = aTarget.content;
+          content.setAttribute("origin", this.content.getAttribute("origin"));
+          content.popupnotificationanchor.className = this.content.popupnotificationanchor.className;
+          content.swapDocShells(this.content);
         ]]></body>
       </method>
 
       <method name="setDecorationAttributes">
         <parameter name="aTarget"/>
         <body><![CDATA[
           if (this.hasAttribute("customSize"))
             aTarget.setAttribute("customSize", this.getAttribute("customSize"));
@@ -204,91 +245,117 @@
 
       <method name="swapWindows">
         <body><![CDATA[
         let deferred = Promise.defer();
         let title = this.getAttribute("label");
         if (this.chatbar) {
           this.chatbar.detachChatbox(this, { "centerscreen": "yes" }).then(
             chatbox => {
-              chatbox.contentWindow.document.title = title;
+              chatbox.content.messageManager.sendAsyncMessage("Social:SetDocumentTitle", {
+                title: title
+              });
               deferred.resolve(chatbox);
             }
           );
         } else {
           // attach this chatbox to the topmost browser window
           let Chat = Cu.import("resource:///modules/Chat.jsm").Chat;
           let win = Chat.findChromeWindowForChats();
           let chatbar = win.document.getElementById("pinnedchats");
           let origin = this.content.getAttribute("origin");
-          let cb = chatbar.openChat(origin, title, "about:blank");
-          this.setDecorationAttributes(cb);
+          let cb = chatbar.openChat({
+            origin: origin,
+            title: title,
+            url: "about:blank"
+          });
 
           cb.promiseChatLoaded.then(
             () => {
+              this.setDecorationAttributes(cb);
+
               this.swapDocShells(cb);
 
               chatbar.focus();
               this.close();
 
               // chatboxForURL is a map of URL -> chatbox used to avoid opening
               // duplicate chat windows. Ensure reattached chat windows aren't
               // registered with about:blank as their URL, otherwise reattaching
               // more than one chat window isn't possible.
               chatbar.chatboxForURL.delete("about:blank");
               chatbar.chatboxForURL.set(this.src, Cu.getWeakReference(cb));
 
-              let attachEvent = new cb.contentWindow.CustomEvent("socialFrameAttached", {
-                bubbles: true,
-                cancelable: true,
+              cb.content.messageManager.sendAsyncMessage("Social:CustomEvent", {
+                name: "socialFrameAttached"
               });
-              cb.contentDocument.dispatchEvent(attachEvent);
 
               deferred.resolve(cb);
             }
           );
         }
         return deferred.promise;
         ]]></body>
       </method>
 
       <method name="toggle">
         <body><![CDATA[
           this.minimized = !this.minimized;
         ]]></body>
       </method>
+
+      <method name="setTitle">
+        <body><![CDATA[
+          try {
+            this.setAttribute("label", this.content.contentTitle);
+          } catch (ex) {}
+          if (this.chatbar)
+            this.chatbar.updateTitlebar(this);
+        ]]></body>
+      </method>
+
+      <method name="receiveMessage">
+        <parameter name="aMessage" />
+        <body><![CDATA[
+          switch (aMessage.name) {
+            case "DOMTitleChanged":
+              this.setTitle();
+              break;
+          }
+        ]]></body>
+      </method>
     </implementation>
 
     <handlers>
       <handler event="focus" phase="capturing">
         if (this.chatbar)
           this.chatbar.selectedChat = this;
       </handler>
-      <handler event="DOMTitleChanged"><![CDATA[
-        this.setAttribute('label', this.contentDocument.title);
-        if (this.chatbar)
-          this.chatbar.updateTitlebar(this);
-      ]]></handler>
+      <handler event="DOMTitleChanged">
+        this.setTitle();
+      </handler>
       <handler event="DOMLinkAdded"><![CDATA[
-        // much of this logic is from DOMLinkHandler in browser.js
-        // this sets the presence icon for a chat user, we simply use favicon style updating
+        // Much of this logic is from DOMLinkHandler in browser.js.
+        // This sets the presence icon for a chat user, we simply use favicon
+        // style updating.
         let link = event.originalTarget;
         let rel = link.rel && link.rel.toLowerCase();
         if (!link || !link.ownerDocument || !rel || !link.href)
           return;
         if (link.rel.indexOf("icon") < 0)
           return;
 
-        let ContentLinkHandler = Cu.import("resource:///modules/ContentLinkHandler.jsm", {}).ContentLinkHandler;
+        let ContentLinkHandler = Cu.import("resource:///modules/ContentLinkHandler.jsm", {})
+          .ContentLinkHandler;
         let uri = ContentLinkHandler.getLinkIconURI(link);
         if (!uri)
           return;
 
-        // we made it this far, use it
-        this.setAttribute('image', uri.spec);
+        // We made it this far, use it.
+        this.setAttribute("image", uri.spec);
         if (this.chatbar)
           this.chatbar.updateTitlebar(this);
       ]]></handler>
       <handler event="transitionend">
         if (this.isActive == this.minimized)
           this.isActive = !this.minimized;
       </handler>
     </handlers>
@@ -323,17 +390,17 @@
       <field name="nub" readonly="true">
         document.getAnonymousElementByAttribute(this, "anonid", "nub");
       </field>
 
       <method name="focus">
         <body><![CDATA[
           if (!this.selectedChat)
             return;
-          Services.focus.focusedWindow = this.selectedChat.contentWindow;
+          this.selectedChat.content.messageManager.sendAsyncMessage("Social:EnsureFocus");
         ]]></body>
       </method>
 
       <method name="_isChatFocused">
         <parameter name="aChatbox"/>
         <body><![CDATA[
           // If there are no XBL bindings for the chat it can't be focused.
           if (!aChatbox.content)
@@ -494,17 +561,17 @@
         <body><![CDATA[
           // we ensure that the cached width for a child of this type is
           // up-to-date so we can use it when resizing.
           this.getTotalChildWidth(aChatbox);
           aChatbox.collapsed = true;
           aChatbox.isActive = false;
           let menu = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuitem");
           menu.setAttribute("class", "menuitem-iconic");
-          menu.setAttribute("label", aChatbox.contentDocument.title);
+          menu.setAttribute("label", aChatbox.content.contentTitle);
           menu.setAttribute("image", aChatbox.getAttribute("image"));
           menu.chat = aChatbox;
           this.menuitemMap.set(aChatbox, menu);
           this.menupopup.appendChild(menu);
           this.nub.collapsed = false;
         ]]></body>
       </method>
 
@@ -563,57 +630,57 @@
             this.menuitemMap.delete(aChatbox);
             this.menupopup.removeChild(menuitem);
           }
           this.chatboxForURL.delete(aChatbox.src);
         ]]></body>
       </method>
 
       <method name="openChat">
-        <parameter name="aOrigin"/>
-        <parameter name="aTitle"/>
-        <parameter name="aURL"/>
-        <parameter name="aMode"/>
+        <parameter name="aOptions"/>
         <parameter name="aCallback"/>
         <body><![CDATA[
-          let cb = this.chatboxForURL.get(aURL);
+          let {origin, title, url, mode} = aOptions;
+          let cb = this.chatboxForURL.get(url);
           if (cb && (cb = cb.get())) {
             // A chatbox is still alive to us when it's parented and still has
             // content.
-            if (cb.parentNode && cb.contentWindow) {
-              this.showChat(cb, aMode);
+            if (cb.parentNode) {
+              this.showChat(cb, mode);
               if (aCallback) {
                 if (cb._callbacks == null) {
                   // Chatbox has already been created, so callback now.
                   aCallback(cb);
                 } else {
                   // Chatbox is yet to have bindings created...
                   cb._callbacks.push(aCallback);
                 }
               }
               return cb;
             }
-            this.chatboxForURL.delete(aURL);
+            this.chatboxForURL.delete(url);
           }
           cb = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "chatbox");
           cb._callbacks = [];
           if (aCallback) {
             // _callbacks is a javascript property instead of a <field> as it
             // must exist before the (possibly delayed) bindings are created.
             cb._callbacks.push(aCallback);
           }
+
+          cb.remote = !!aOptions.remote;
           // src also a javascript property; the src attribute is set in the ctor.
-          cb.src = aURL;
-          if (aMode == "minimized")
+          cb.src = url;
+          if (mode == "minimized")
             cb.setAttribute("minimized", "true");
-          cb.setAttribute("origin", aOrigin);
-          cb.setAttribute("label", aTitle);
+          cb.setAttribute("origin", origin);
+          cb.setAttribute("label", title);
           this.insertBefore(cb, this.firstChild);
           this.selectedChat = cb;
-          this.chatboxForURL.set(aURL, Cu.getWeakReference(cb));
+          this.chatboxForURL.set(url, Cu.getWeakReference(cb));
           this.resize();
           return cb;
         ]]></body>
       </method>
 
       <method name="resize">
         <body><![CDATA[
         // Checks the current size against the collapsed state of children
@@ -709,31 +776,28 @@
             if (event.target != otherWin.document)
               return;
 
             if (aChatbox.hasAttribute("customSize")) {
               otherWin.document.getElementById("chat-window").
                 setAttribute("customSize", aChatbox.getAttribute("customSize"));
             }
 
-            let document = aChatbox.contentDocument;
-            let detachEvent = new aChatbox.contentWindow.CustomEvent("socialFrameDetached", {
-              bubbles: true,
-              cancelable: true,
-            });
-
             otherWin.removeEventListener("load", _chatLoad, true);
             let otherChatbox = otherWin.document.getElementById("chatter");
             aChatbox.setDecorationAttributes(otherChatbox);
             aChatbox.swapDocShells(otherChatbox);
+
             aChatbox.close();
             chatbar.chatboxForURL.set(aChatbox.src, Cu.getWeakReference(otherChatbox));
 
             // All processing is done, now we can fire the event.
-            document.dispatchEvent(detachEvent);
+            otherChatbox.content.messageManager.sendAsyncMessage("Social:CustomEvent", {
+              name: "socialFrameDetached"
+            });
 
             deferred.resolve(otherChatbox);
           }, true);
           return deferred.promise;
         ]]></body>
       </method>
 
     </implementation>
--- a/browser/base/content/socialmarks.xml
+++ b/browser/base/content/socialmarks.xml
@@ -159,27 +159,27 @@
 
         let URLTemplate = provider.markURL;
         let _dataFn;
         if (!pageData) {
           messageManager.addMessageListener("PageMetadata:PageDataResult", _dataFn = (msg) => {
             messageManager.removeMessageListener("PageMetadata:PageDataResult", _dataFn);
             this.loadPanel(msg.json, target);
           });
-          gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetPageData");
+          gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetPageData", null, { target });
           return;
         }
-        // if this is a share of a selected item, get any microdata
-        if (!pageData.microdata && target) {
-          messageManager.addMessageListener("PageMetadata:MicrodataResult", _dataFn = (msg) => {
-            messageManager.removeMessageListener("PageMetadata:MicrodataResult", _dataFn);
-            pageData.microdata = msg.data;
+        // if this is a share of a selected item, get any microformats
+        if (!pageData.microformats && target) {
+          messageManager.addMessageListener("PageMetadata:MicroformatsResult", _dataFn = (msg) => {
+            messageManager.removeMessageListener("PageMetadata:MicroformatsResult", _dataFn);
+            pageData.microformats = msg.data;
             this.loadPanel(pageData, target);
           });
-          gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetMicrodata", null, { target });
+          gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetMicroformats", null, { target });
           return;
         }
         this.pageData = pageData;
 
         let endpoint = OpenGraphBuilder.generateEndpointURL(URLTemplate, this.pageData);
 
         // setup listeners
         let DOMContentLoaded = (event) => {
--- a/browser/base/content/sync/genericChange.js
+++ b/browser/base/content/sync/genericChange.js
@@ -116,17 +116,17 @@ var Change = {
   _clearStatus: function _clearStatus() {
     this._status.value = "";
     this._statusIcon.removeAttribute("status");
   },
 
   _updateStatus: function Change__updateStatus(str, state) {
      this._updateStatusWithString(this._str(str), state);
   },
-  
+
   _updateStatusWithString: function Change__updateStatusWithString(string, state) {
     this._statusRow.hidden = false;
     this._status.value = string;
     this._statusIcon.setAttribute("status", state);
 
     let error = state == "error";
     this._dialog.getButton("cancel").disabled = !error;
     this._dialog.getButton("finish").disabled = !error;
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -2496,16 +2496,17 @@
             // fire the beforeunload event in the process.  Close the other
             // window if this was its last tab.
             if (!remoteBrowser._beginRemoveTab(aOtherTab, true, true))
               return;
 
             let modifiedAttrs = [];
             if (aOtherTab.hasAttribute("muted")) {
               aOurTab.setAttribute("muted", "true");
+              aOurTab.muteReason = aOtherTab.muteReason;
               ourBrowser.mute();
               modifiedAttrs.push("muted");
             }
             if (aOtherTab.hasAttribute("soundplaying")) {
               aOurTab.setAttribute("soundplaying", "true");
               modifiedAttrs.push("soundplaying");
             }
             if (aOtherTab.hasAttribute("usercontextid")) {
@@ -5374,17 +5375,17 @@
           }
 
           // For telemetry, the first frame interval is not useful since it may represent an interval
           // to a relatively old frame (prior to recording start). So we'll ignore it for the average.
           if (frameCount > 1) {
             let averageInterval = 0;
             for (let i = 1; i < frameCount; i++) {
               averageInterval += intervals[i];
-            };
+            }
             averageInterval = averageInterval / (frameCount - 1);
 
             Services.telemetry.getHistogramById("FX_TAB_ANIM_ANY_FRAME_INTERVAL_MS").add(averageInterval);
 
             if (aTab._recordingTabOpenPlain) {
               delete aTab._recordingTabOpenPlain;
               // While we do have a telemetry probe NEWTAB_PAGE_ENABLED to monitor newtab preview, it'll be
               // easier to overview the data without slicing by it. Hence the additional histograms with _PREVIEW.
@@ -5497,17 +5498,35 @@
 
       <handler event="click"><![CDATA[
         if (event.button != 1)
           return;
 
         if (event.target.localName == "tab") {
           this.tabbrowser.removeTab(event.target, {animate: true, byMouse: true});
         } else if (event.originalTarget.localName == "box") {
-          BrowserOpenTab();
+          // The user middleclicked an open space on the tabstrip. This could
+          // be because they intend to open a new tab, but it could also be
+          // because they just removed a tab and they now middleclicked on the
+          // resulting space while that tab is closing. In that case, we don't
+          // want to open a tab. So if we're removing one or more tabs, and
+          // the tab click is before the end of the last visible tab, we do
+          // nothing.
+          if (this.tabbrowser._removingTabs.length) {
+            let visibleTabs = this.tabbrowser.visibleTabs;
+            let ltr = (window.getComputedStyle(this, null).direction == "ltr");
+            let lastTab = visibleTabs[visibleTabs.length - 1];
+            let endOfTab = lastTab.getBoundingClientRect()[ltr ? "right" : "left"];
+            if ((ltr && event.clientX > endOfTab) ||
+                (!ltr && event.clientX < endOfTab)) {
+              BrowserOpenTab();
+            }
+          } else {
+            BrowserOpenTab();
+          }
         } else {
           return;
         }
 
         event.stopPropagation();
       ]]></handler>
 
       <handler event="keydown" group="system"><![CDATA[
@@ -6075,16 +6094,35 @@
           return this.getAttribute("pinned") == "true";
         </getter>
       </property>
       <property name="hidden" readonly="true">
         <getter>
           return this.getAttribute("hidden") == "true";
         </getter>
       </property>
+      <property name="muted" readonly="true">
+        <getter>
+          return this.getAttribute("muted") == "true";
+        </getter>
+      </property>
+      <!--
+      Describes how the tab ended up in this mute state. May be any of:
+
+       - undefined: The tabs mute state has never changed.
+       - null: The mute state was last changed through the UI.
+       - Any string: The ID was changed through an extension API. The string
+                     must be the ID of the extension which changed it.
+      -->
+      <field name="muteReason">undefined</field>
+      <property name="soundPlaying" readonly="true">
+        <getter>
+          return this.getAttribute("soundplaying") == "true";
+        </getter>
+      </property>
 
       <property name="lastAccessed">
         <getter>
           return this._lastAccessed == Infinity ? Date.now() : this._lastAccessed;
         </getter>
         <setter>
           this._lastAccessed = val;
         </setter>
@@ -6157,27 +6195,29 @@
             tabContainer._afterHoveredTab = null;
           }
 
           tabContainer._hoveredTab = null;
         ]]></body>
       </method>
 
       <method name="toggleMuteAudio">
+        <parameter name="aMuteReason"/>
         <body>
         <![CDATA[
           let tabContainer = this.parentNode;
           let browser = this.linkedBrowser;
           if (browser.audioMuted) {
             browser.unmute();
             this.removeAttribute("muted");
           } else {
             browser.mute();
             this.setAttribute("muted", "true");
           }
+          this.muteReason = aMuteReason || null;
           tabContainer.tabbrowser._tabAttrModified(this, ["muted"]);
         ]]>
         </body>
       </method>
 
       <method name="setUserContextId">
         <parameter name="aUserContextId"/>
         <body>
--- a/browser/base/content/test/chat/browser.ini
+++ b/browser/base/content/test/chat/browser.ini
@@ -1,9 +1,11 @@
-[DEFAULT]
-skip-if = buildapp == 'mulet' || e10s
-support-files =
-  head.js
-  chat.html
-
-[browser_chatwindow.js]
-[browser_focus.js]
-[browser_tearoff.js]
+[DEFAULT]
+skip-if = buildapp == 'mulet' || e10s
+support-files =
+  head.js
+  chat.html
+
+[browser_chatwindow.js]
+skip-if = true # Bug 1245937 - Intermittent failures/timeouts.
+[browser_focus.js]
+[browser_tearoff.js]
+skip-if = true # Bug 1245805 - tearing off chat windows causes a browser crash.
--- a/browser/base/content/test/chat/browser_chatwindow.js
+++ b/browser/base/content/test/chat/browser_chatwindow.js
@@ -20,19 +20,17 @@ add_chat_task(function* testOpenCloseCha
   Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
 
   chatbox.toggle();
   is(chatbox.minimized, true, "chat is now minimized");
   // was no other chat to select, so selected becomes null.
   is(chatbar.selectedChat, null);
 
   // We check the content gets an unload event as we close it.
-  let promiseClosed = promiseOneEvent(chatbox.content, "unload", true);
   chatbox.close();
-  yield promiseClosed;
 });
 
 // In this case we open a chat minimized, then request the same chat again
 // without specifying minimized.  On that second call the chat should open,
 // selected, and no longer minimized.
 add_chat_task(function* testMinimized() {
   let chatbox = yield promiseOpenChat("http://example.com", "minimized");
   Assert.strictEqual(chatbox, chatbar.selectedChat);
@@ -77,18 +75,19 @@ add_chat_task(function* testOpenTwiceCal
 add_chat_task(function* testOpenTwiceCallbacks() {
   yield promiseOpenChatCallback("http://example.com");
   yield promiseOpenChatCallback("http://example.com");
 });
 
 // Bug 817782 - check chats work in new top-level windows.
 add_chat_task(function* testSecondTopLevelWindow() {
   const chatUrl = "http://example.com";
-  let secondWindow = OpenBrowserWindow();
-  yield promiseOneEvent(secondWindow, "load");
+  let winPromise = BrowserTestUtils.waitForNewWindow();
+  OpenBrowserWindow();
+  let secondWindow = yield winPromise;
   yield promiseOpenChat(chatUrl);
   // the chat was created - let's make sure it was created in the second window.
   Assert.equal(numChatsInWindow(window), 0, "main window has no chats");
   Assert.equal(numChatsInWindow(secondWindow), 1, "second window has 1 chat");
   secondWindow.close();
 });
 
 // Test that findChromeWindowForChats() returns the expected window.
--- a/browser/base/content/test/chat/browser_focus.js
+++ b/browser/base/content/test/chat/browser_focus.js
@@ -46,47 +46,60 @@ add_chat_task(function* testDefaultFocus
   // we used the default focus behaviour, which means that because this was
   // not the direct result of user action the chat should not be focused.
   Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
   Assert.ok(isTabFocused(), "the tab should remain focused.");
   Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
 });
 
 // Test default focus via user input.
-add_chat_task(function* testDefaultFocus() {
+add_chat_task(function* testDefaultFocusUserInput() {
+  todo(false, "BrowserTestUtils.synthesizeMouseAtCenter doesn't move the user " +
+    "focus to the chat window, even though we're recording a click correctly.");
+  return;
+
   yield setUp();
-  let tab = gBrowser.selectedTab;
+  let browser = gBrowser.selectedTab.linkedBrowser;
+  let mm = browser.messageManager;
+
   let deferred = Promise.defer();
-  let button = tab.linkedBrowser.contentDocument.getElementById("chat-opener");
-  button.addEventListener("click", function onclick() {
-    button.removeEventListener("click", onclick);
-    promiseOpenChat("http://example.com").then(
-      chat => deferred.resolve(chat)
-    );
-  })
+  mm.addMessageListener("ChatOpenerClicked", function handler() {
+    mm.removeMessageListener("ChatOpenerClicked", handler);
+    promiseOpenChat("http://example.com").then(chat => deferred.resolve(chat));
+  });
+
+  yield ContentTask.spawn(browser, null, function* () {
+    let button = content.document.getElementById("chat-opener");
+    button.addEventListener("click", function onclick() {
+      button.removeEventListener("click", onclick);
+      sendAsyncMessage("ChatOpenerClicked");
+    });
+  });
   // Note we must use synthesizeMouseAtCenter() rather than calling
   // .click() directly as this causes nsIDOMWindowUtils.isHandlingUserInput
   // to be true.
-  EventUtils.synthesizeMouseAtCenter(button, {}, button.ownerDocument.defaultView);
+  yield BrowserTestUtils.synthesizeMouseAtCenter("#chat-opener", {}, browser);
   let chat = yield deferred.promise;
 
   // we use the default focus behaviour but the chat was opened via user input,
   // so the chat should be focused.
   Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
+  yield promiseWaitForCondition(() => !isTabFocused());
   Assert.ok(!isTabFocused(), "the tab should have lost focus.");
   Assert.ok(isChatFocused(chat), "the chat should have got focus.");
 });
 
 // We explicitly ask for the chat to be focused.
 add_chat_task(function* testExplicitFocus() {
   yield setUp();
   let chat = yield promiseOpenChat("http://example.com", undefined, true);
   // we use the default focus behaviour, which means that because this was
   // not the direct result of user action the chat should not be focused.
   Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
+  yield promiseWaitForCondition(() => !isTabFocused());
   Assert.ok(!isTabFocused(), "the tab should have lost focus.");
   Assert.ok(isChatFocused(chat), "the chat should have got focus.");
 });
 
 // Open a minimized chat via default focus behaviour - it will open and not
 // have focus.  Then open the same chat without 'minimized' - it will be
 // restored but should still not have grabbed focus.
 add_chat_task(function* testNoFocusOnAutoRestore() {
@@ -109,127 +122,135 @@ add_chat_task(function* testFocusOnExpli
   let chat = yield promiseOpenChat("http://example.com");
   Assert.ok(!chat.minimized, "chat should have been opened restored");
   Assert.ok(isTabFocused(), "the tab should remain focused.");
   Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
   chat.minimized = true;
   Assert.ok(isTabFocused(), "tab should still be focused");
   Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
 
-  let promise = promiseOneEvent(chat.contentWindow, "focus");
+  let promise = promiseOneMessage(chat.content, "Social:FocusEnsured");
   // pretend we clicked on the titlebar
   chat.onTitlebarClick({button: 0});
   yield promise; // wait for focus event.
   Assert.ok(!chat.minimized, "chat should have been restored");
   Assert.ok(isChatFocused(chat), "chat should be focused");
   Assert.strictEqual(chat, chatbar.selectedChat, "chat is marked selected");
 });
 
 // Open 2 chats and give 1 focus.  Minimize the focused one - the second
 // should get focus.
 add_chat_task(function* testMinimizeFocused() {
   yield setUp();
   let chat1 = yield promiseOpenChat("http://example.com#1");
   let chat2 = yield promiseOpenChat("http://example.com#2");
   Assert.equal(numChatsInWindow(window), 2, "2 chats open");
   Assert.strictEqual(chatbar.selectedChat, chat2, "chat2 is selected");
-  let promise = promiseOneEvent(chat1.contentWindow, "focus");
+  let promise = promiseOneMessage(chat1.content, "Social:FocusEnsured");
   chatbar.selectedChat = chat1;
   chatbar.focus();
   yield promise; // wait for chat1 to get focus.
   Assert.strictEqual(chat1, chatbar.selectedChat, "chat1 is marked selected");
   Assert.notStrictEqual(chat2, chatbar.selectedChat, "chat2 is not marked selected");
-  promise = promiseOneEvent(chat2.contentWindow, "focus");
+
+  todo(false, "Bug 1245803 should re-enable the test below to have a chat window " +
+    "re-gain focus when another chat window is minimized.");
+  return;
+
+  promise = promiseOneMessage(chat2.content, "Social:FocusEnsured");
   chat1.minimized = true;
   yield promise; // wait for chat2 to get focus.
   Assert.notStrictEqual(chat1, chatbar.selectedChat, "chat1 is not marked selected");
   Assert.strictEqual(chat2, chatbar.selectedChat, "chat2 is marked selected");
 });
 
 // Open 2 chats, select and focus the second.  Pressing the TAB key should
 // cause focus to move between all elements in our chat window before moving
 // to the next chat window.
 add_chat_task(function* testTab() {
   yield setUp();
 
   function sendTabAndWaitForFocus(chat, eltid) {
-    let doc = chat.contentDocument;
     EventUtils.sendKey("tab");
-    // ideally we would use the 'focus' event here, but that doesn't work
-    // as expected for the iframe - the iframe itself never gets the focus
-    // event (apparently the sub-document etc does.)
-    // So just poll for the correct element getting focus...
-    let deferred = Promise.defer();
-    let tries = 0;
-    let interval = setInterval(function() {
-      if (tries >= 30) {
-        clearInterval(interval);
-        deferred.reject("never got focus");
-        return;
-      }
-      tries ++;
-      let elt = eltid ? doc.getElementById(eltid) : doc.documentElement;
-      if (doc.activeElement == elt) {
-        clearInterval(interval);
-        deferred.resolve();
-      }
-      info("retrying wait for focus: " + tries);
-      info("(the active element is " + doc.activeElement + "/" + doc.activeElement.getAttribute("id") + ")");
-    }, 100);
-    info("waiting for element " + eltid + " to get focus");
-    return deferred.promise;
+
+    return ContentTask.spawn(chat.content, { eltid: eltid }, function* (args) {
+      let doc = content.document;
+
+      // ideally we would use the 'focus' event here, but that doesn't work
+      // as expected for the iframe - the iframe itself never gets the focus
+      // event (apparently the sub-document etc does.)
+      // So just poll for the correct element getting focus...
+      yield new Promise(function(resolve, reject) {
+        let tries = 0;
+        let interval = content.setInterval(function() {
+          if (tries >= 30) {
+            clearInterval(interval);
+            reject("never got focus");
+            return;
+          }
+          tries++;
+          let elt = args.eltid ? doc.getElementById(args.eltid) : doc.documentElement;
+          if (doc.activeElement == elt) {
+            content.clearInterval(interval);
+            resolve();
+          }
+          info("retrying wait for focus: " + tries);
+          info("(the active element is " + doc.activeElement + "/" +
+            doc.activeElement.getAttribute("id") + ")");
+        }, 100);
+        info("waiting for element " + args.eltid + " to get focus");
+      });
+    });
   }
 
   let chat1 = yield promiseOpenChat(CHAT_URL + "#1");
   let chat2 = yield promiseOpenChat(CHAT_URL + "#2");
   chatbar.selectedChat = chat2;
-  let promise = promiseOneEvent(chat2.contentWindow, "focus");
+  let promise = promiseOneMessage(chat2.content, "Social:FocusEnsured");
   chatbar.focus();
   info("waiting for second chat to get focus");
   yield promise;
 
   // Our chats have 3 focusable elements, so it takes 4 TABs to move
   // to the new chat.
   yield sendTabAndWaitForFocus(chat2, "input1");
-  Assert.equal(chat2.contentDocument.activeElement.getAttribute("id"), "input1",
-               "first input field has focus");
   Assert.ok(isChatFocused(chat2), "new chat still focused after first tab");
 
   yield sendTabAndWaitForFocus(chat2, "input2");
   Assert.ok(isChatFocused(chat2), "new chat still focused after tab");
-  Assert.equal(chat2.contentDocument.activeElement.getAttribute("id"), "input2",
-               "second input field has focus");
 
   yield sendTabAndWaitForFocus(chat2, "iframe");
   Assert.ok(isChatFocused(chat2), "new chat still focused after tab");
-  Assert.equal(chat2.contentDocument.activeElement.getAttribute("id"), "iframe",
-               "iframe has focus");
 
   // this tab now should move to the next chat, but focus the
   // document element itself (hence the null eltid)
   yield sendTabAndWaitForFocus(chat1, null);
   Assert.ok(isChatFocused(chat1), "first chat is focused");
 });
 
 // Open a chat and focus an element other than the first. Move focus to some
 // other item (the tab itself in this case), then focus the chatbar - the
 // same element that was previously focused should still have focus.
 add_chat_task(function* testFocusedElement() {
   yield setUp();
 
   // open a chat with focus requested.
   let chat = yield promiseOpenChat(CHAT_URL, undefined, true);
 
-  chat.contentDocument.getElementById("input2").focus();
+  yield ContentTask.spawn(chat.content, null, function* () {
+    content.document.getElementById("input2").focus();
+  });
 
   // set focus to the tab.
   let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
   let promise = promiseOneEvent(tabb.contentWindow, "focus");
   Services.focus.moveFocus(tabb.contentWindow, null, Services.focus.MOVEFOCUS_ROOT, 0);
   yield promise;
 
-  promise = promiseOneEvent(chat.contentWindow, "focus");
+  promise = promiseOneMessage(chat.content, "Social:FocusEnsured");
   chatbar.focus();
   yield promise;
 
-  Assert.equal(chat.contentDocument.activeElement.getAttribute("id"), "input2",
-               "correct input field still has focus");
+  yield ContentTask.spawn(chat.content, null, function* () {
+    is(content.document.activeElement.getAttribute("id"), "input2",
+      "correct input field still has focus");
+  });
 });
--- a/browser/base/content/test/chat/browser_tearoff.js
+++ b/browser/base/content/test/chat/browser_tearoff.js
@@ -14,41 +14,44 @@ function promiseNewWindowLoaded() {
     onOpenWindow: function(xulwindow) {
       var domwindow = xulwindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                             .getInterface(Components.interfaces.nsIDOMWindow);
       Services.wm.removeListener(this);
       // wait for load to ensure the window is ready for us to test
       domwindow.addEventListener("load", function _load(event) {
         let doc = domwindow.document;
         if (event.target != doc)
-            return;
+          return;
         domwindow.removeEventListener("load", _load);
         deferred.resolve(domwindow);
       });
     },
   });
   return deferred.promise;
 }
 
 add_chat_task(function* testTearoffChat() {
   let chatbox = yield promiseOpenChat("http://example.com");
   Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
 
-  let chatDoc = chatbox.contentDocument;
-  let chatTitle = chatDoc.title;
+  let chatTitle = yield ContentTask.spawn(chatbox.content, null, function* () {
+    let chatDoc = content.document;
+
+    // Mutate the chat document a bit before we tear it off.
+    let div = chatDoc.createElement("div");
+    div.setAttribute("id", "testdiv");
+    div.setAttribute("test", "1");
+    chatDoc.body.appendChild(div);
+
+    return chatDoc.title;
+  });
 
   Assert.equal(chatbox.getAttribute("label"), chatTitle,
                "the new chatbox should show the title of the chat window");
 
-  // mutate the chat document a bit before we tear it off.
-  let div = chatDoc.createElement("div");
-  div.setAttribute("id", "testdiv");
-  div.setAttribute("test", "1");
-  chatDoc.body.appendChild(div);
-
   // chatbox is open, lets detach. The new chat window will be caught in
   // the window watcher below
   let promise = promiseNewWindowLoaded();
 
   let swap = document.getAnonymousElementByAttribute(chatbox, "anonid", "swap");
   swap.click();
 
   // and wait for the new window.
@@ -56,34 +59,38 @@ add_chat_task(function* testTearoffChat(
 
   Assert.equal(domwindow.document.documentElement.getAttribute("windowtype"), "Social:Chat", "Social:Chat window opened");
   Assert.equal(numChatsInWindow(window), 0, "should be no chats in the chat bar");
 
   // get the chatbox from the new window.
   chatbox = domwindow.document.getElementById("chatter")
   Assert.equal(chatbox.getAttribute("label"), chatTitle, "window should have same title as chat");
 
-  div = chatbox.contentDocument.getElementById("testdiv");
-  Assert.equal(div.getAttribute("test"), "1", "docshell should have been swapped");
-  div.setAttribute("test", "2");
+  yield ContentTask.spawn(chatbox.content, null, function* () {
+    div = content.document.getElementById("testdiv");
+    is(div.getAttribute("test"), "1", "docshell should have been swapped");
+    div.setAttribute("test", "2");
+  });
 
   // swap the window back to the chatbar
   promise = promiseOneEvent(domwindow, "unload");
   swap = domwindow.document.getAnonymousElementByAttribute(chatbox, "anonid", "swap");
   swap.click();
 
   yield promise;
 
   Assert.equal(numChatsInWindow(window), 1, "chat should be docked back in the window");
   chatbox = chatbar.selectedChat;
   Assert.equal(chatbox.getAttribute("label"), chatTitle,
                "the new chatbox should show the title of the chat window again");
 
-  div = chatbox.contentDocument.getElementById("testdiv");
-  Assert.equal(div.getAttribute("test"), "2", "docshell should have been swapped");
+  yield ContentTask.spawn(chatbox.content, null, function* () {
+    let div = content.document.getElementById("testdiv");
+    is(div.getAttribute("test"), "2", "docshell should have been swapped");
+  });
 });
 
 // Similar test but with 2 chats.
 add_chat_task(function* testReattachTwice() {
   let chatbox1 = yield promiseOpenChat("http://example.com#1");
   let chatbox2 = yield promiseOpenChat("http://example.com#2");
   Assert.equal(numChatsInWindow(window), 2, "both chats should be docked in the window");
 
--- a/browser/base/content/test/chat/head.js
+++ b/browser/base/content/test/chat/head.js
@@ -10,58 +10,73 @@ const kDefaultButtonSet = new Set(["mini
 function promiseOpenChat(url, mode, focus, buttonSet = null) {
   let uri = Services.io.newURI(url, null, null);
   let origin = uri.prePath;
   let title = origin;
   let deferred = Promise.defer();
   // we just through a few hoops to ensure the content document is fully
   // loaded, otherwise tests that rely on that content may intermittently fail.
   let callback = function(chatbox) {
-    if (chatbox.contentDocument.readyState == "complete") {
-      // already loaded.
+    let mm = chatbox.content.messageManager;
+    mm.sendAsyncMessage("WaitForDOMContentLoaded");
+    mm.addMessageListener("DOMContentLoaded", function cb() {
+      mm.removeMessageListener("DOMContentLoaded", cb);
       deferred.resolve(chatbox);
-      return;
-    }
-    chatbox.addEventListener("load", function onload(event) {
-      if (event.target != chatbox.contentDocument || chatbox.contentDocument.location.href == "about:blank") {
-        return;
-      }
-      chatbox.removeEventListener("load", onload, true);
-      deferred.resolve(chatbox);
-    }, true);
+    });
   }
-  let chatbox = Chat.open(null, origin, title, url, mode, focus, callback);
+  let chatbox = Chat.open(null, {
+    origin: origin,
+    title: title,
+    url: url,
+    mode: mode,
+    focus: focus
+  }, callback);
   if (buttonSet) {
     chatbox.setAttribute("buttonSet", buttonSet);
   }
   return deferred.promise;
 }
 
 // Opens a chat, returns a promise resolved when the chat callback fired.
 function promiseOpenChatCallback(url, mode) {
   let uri = Services.io.newURI(url, null, null);
   let origin = uri.prePath;
   let title = origin;
   let deferred = Promise.defer();
   let callback = deferred.resolve;
-  Chat.open(null, origin, title, url, mode, undefined, callback);
+  Chat.open(null, {
+    origin: origin,
+    title: title,
+    url: url,
+    mode: mode
+  }, callback);
   return deferred.promise;
 }
 
 // Opens a chat, returns the chat window's promise which fires when the chat
 // starts loading.
 function promiseOneEvent(target, eventName, capture) {
   let deferred = Promise.defer();
   target.addEventListener(eventName, function handler(event) {
     target.removeEventListener(eventName, handler, capture);
     deferred.resolve();
   }, capture);
   return deferred.promise;
 }
 
+function promiseOneMessage(target, messageName) {
+  return new Promise(resolve => {
+    let mm = target.messageManager;
+    mm.addMessageListener(messageName, function handler() {
+      mm.removeMessageListener(messageName, handler);
+      resolve();
+    });
+  });
+}
+
 // Return the number of chats in a browser window.
 function numChatsInWindow(win) {
   let chatbar = win.document.getElementById("pinnedchats");
   return chatbar.childElementCount;
 }
 
 function promiseWaitForFocus() {
   let deferred = Promise.defer();
@@ -88,8 +103,36 @@ function add_chat_task(genFunction) {
         if (win.closed) {
           continue;
         }
         win.close();
       }
     }
   });
 }
+
+function waitForCondition(condition, nextTest, errorMsg) {
+  var tries = 0;
+  var interval = setInterval(function() {
+    if (tries >= 100) {
+      ok(false, errorMsg);
+      moveOn();
+    }
+    var conditionPassed;
+    try {
+      conditionPassed = condition();
+    } catch (e) {
+      ok(false, e + "\n" + e.stack);
+      conditionPassed = false;
+    }
+    if (conditionPassed) {
+      moveOn();
+    }
+    tries++;
+  }, 100);
+  var moveOn = function() { clearInterval(interval); nextTest(); };
+}
+
+function promiseWaitForCondition(aConditionFn) {
+  return new Promise((resolve, reject) => {
+    waitForCondition(aConditionFn, resolve, "Condition didn't pass.");
+  });
+}
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -152,17 +152,19 @@ skip-if = os == "mac" # The Fitt's Law b
 [browser_beforeunload_duplicate_dialogs.js]
 [browser_blob-channelname.js]
 [browser_bookmark_titles.js]
 skip-if = buildapp == 'mulet' || toolkit == "windows" # Disabled on Windows due to frequent failures (bugs 825739, 841341)
 [browser_bug304198.js]
 [browser_bug321000.js]
 skip-if = true # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
 [browser_bug329212.js]
+skip-if = e10s # Bug 1236991 - Update or remove tests that use fillInPageTooltip
 [browser_bug331772_xul_tooltiptext_in_html.js]
+skip-if = e10s # Bug 1236991 - Update or remove tests that use fillInPageTooltip
 [browser_bug356571.js]
 [browser_bug380960.js]
 [browser_bug386835.js]
 [browser_bug406216.js]
 [browser_bug409481.js]
 [browser_bug409624.js]
 [browser_bug413915.js]
 [browser_bug416661.js]
@@ -205,16 +207,17 @@ skip-if = buildapp == 'mulet' || e10s # 
 [browser_bug550565.js]
 [browser_bug553455.js]
 skip-if = buildapp == 'mulet' # Bug 1066070 - I don't think either popup notifications nor addon install stuff works on mulet?
 [browser_bug555224.js]
 [browser_bug555767.js]
 [browser_bug556061.js]
 [browser_bug559991.js]
 [browser_bug561623.js]
+skip-if = e10s # Bug 1236991 - Update or remove tests that use fillInPageTooltip
 [browser_bug561636.js]
 [browser_bug562649.js]
 [browser_bug563588.js]
 [browser_bug565575.js]
 [browser_bug565667.js]
 skip-if = toolkit != "cocoa"
 [browser_bug567306.js]
 [browser_bug575561.js]
@@ -222,16 +225,17 @@ skip-if = toolkit != "cocoa"
 [browser_bug577121.js]
 [browser_bug578534.js]
 [browser_bug579872.js]
 [browser_bug580638.js]
 [browser_bug580956.js]
 [browser_bug581242.js]
 [browser_bug581253.js]
 [browser_bug581947.js]
+skip-if = e10s # Bug 1236991 - Update or remove tests that use fillInPageTooltip
 [browser_bug585558.js]
 [browser_bug585785.js]
 [browser_bug585830.js]
 [browser_bug590206.js]
 [browser_bug592338.js]
 [browser_bug594131.js]
 [browser_bug595507.js]
 [browser_bug596687.js]
@@ -315,16 +319,17 @@ support-files = fxa_profile_handler.sjs
 [browser_gestureSupport.js]
 skip-if = e10s # Bug 863514 - no gesture support.
 [browser_getshortcutoruri.js]
 [browser_hide_removing.js]
 [browser_homeDrop.js]
 skip-if = buildapp == 'mulet'
 [browser_identity_UI.js]
 [browser_insecureLoginForms.js]
+[browser_invalid_uri_back_forward_manipulation.js]
 [browser_keywordBookmarklets.js]
 [browser_keywordSearch.js]
 [browser_keywordSearch_postData.js]
 [browser_lastAccessedTab.js]
 skip-if = toolkit == "windows" # Disabled on Windows due to frequent failures (bug 969405)
 [browser_locationBarCommand.js]
 skip-if = os == "linux" # Linux: Intermittent failures, bug 917535
 [browser_locationBarExternalLoad.js]
@@ -461,16 +466,17 @@ support-files =
 [browser_typeAheadFind.js]
 skip-if = buildapp == 'mulet'
 [browser_unknownContentType_title.js]
 [browser_unloaddialogs.js]
 skip-if = e10s # Bug 1100700 - test relies on unload event firing on closed tabs, which it doesn't
 [browser_urlHighlight.js]
 [browser_urlbarAutoFillTrimURLs.js]
 [browser_urlbarCopying.js]
+[browser_urlbarDecode.js]
 [browser_urlbarDelete.js]
 [browser_urlbarEnter.js]
 [browser_urlbarEnterAfterMouseOver.js]
 skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
 [browser_urlbarRevert.js]
 [browser_urlbarSearchSingleWordNotification.js]
 [browser_urlbarSearchSuggestions.js]
 [browser_urlbarSearchSuggestionsNotification.js]
@@ -532,8 +538,10 @@ support-files =
 [browser_domFullscreen_fullscreenMode.js]
 [browser_menuButtonBadgeManager.js]
 [browser_aboutTabCrashed.js]
 skip-if = !e10s || !crashreporter
 [browser_aboutTabCrashed_clearEmail.js]
 skip-if = !e10s || !crashreporter
 [browser_aboutTabCrashed_showForm.js]
 skip-if = !e10s || !crashreporter
+[browser_aboutTabCrashed_withoutDump.js]
+skip-if = !e10s
--- a/browser/base/content/test/general/browser_aboutHealthReport.js
+++ b/browser/base/content/test/general/browser_aboutHealthReport.js
@@ -9,29 +9,27 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 
 const CHROME_BASE = "chrome://mochitests/content/browser/browser/base/content/test/general/";
 const HTTPS_BASE = "https://example.com/browser/browser/base/content/test/general/";
 
 const TELEMETRY_LOG_PREF = "toolkit.telemetry.log.level";
 const telemetryOriginalLogPref = Preferences.get(TELEMETRY_LOG_PREF, null);
 
 const originalReportUrl = Services.prefs.getCharPref("datareporting.healthreport.about.reportUrl");
-const originalReportUrlUnified = Services.prefs.getCharPref("datareporting.healthreport.about.reportUrlUnified");
 
 registerCleanupFunction(function() {
   // Ensure we don't pollute prefs for next tests.
   if (telemetryOriginalLogPref) {
     Preferences.set(TELEMETRY_LOG_PREF, telemetryOriginalLogPref);
   } else {
     Preferences.reset(TELEMETRY_LOG_PREF);
   }
 
   try {
     Services.prefs.setCharPref("datareporting.healthreport.about.reportUrl", originalReportUrl);
-    Services.prefs.setCharPref("datareporting.healthreport.about.reportUrlUnified", originalReportUrlUnified);
     Services.prefs.setBoolPref("datareporting.healthreport.uploadEnabled", true);
   } catch (ex) {}
 });
 
 function fakeTelemetryNow(...args) {
   let date = new Date(...args);
   let scope = {};
   const modules = [
@@ -64,18 +62,16 @@ var gTests = [
 {
   desc: "Test the remote commands",
   setup: Task.async(function*()
   {
     Preferences.set(TELEMETRY_LOG_PREF, "Trace");
     yield setupPingArchive();
     Preferences.set("datareporting.healthreport.about.reportUrl",
                     HTTPS_BASE + "healthreport_testRemoteCommands.html");
-    Preferences.set("datareporting.healthreport.about.reportUrlUnified",
-                    HTTPS_BASE + "healthreport_testRemoteCommands.html");
   }),
   run: function (iframe)
   {
     let deferred = Promise.defer();
     let results = 0;
     try {
       iframe.contentWindow.addEventListener("FirefoxHealthReportTestResponse", function evtHandler(event) {
         let data = event.detail.data;
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_aboutTabCrashed_withoutDump.js
@@ -0,0 +1,44 @@
+"use strict";
+
+const PAGE = "data:text/html,<html><body>A%20regular,%20everyday,%20normal%20page.";
+
+/**
+ * Monkey patches TabCrashHandler.getDumpID to return null in order to test
+ * about:tabcrashed when a dump is not available.
+ */
+add_task(function* setup() {
+  let originalGetDumpID = TabCrashHandler.getDumpID;
+  TabCrashHandler.getDumpID = function(browser) { return null; };
+  registerCleanupFunction(() => {
+    TabCrashHandler.getDumpID = originalGetDumpID;
+  });
+});
+
+/**
+ * Tests tab crash page when a dump is not available.
+ */
+add_task(function* test_without_dump() {
+  return BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: PAGE,
+  }, function*(browser) {
+    let tab = gBrowser.getTabForBrowser(browser);
+    yield BrowserTestUtils.crashBrowser(browser);
+
+    let tabRemovedPromise = BrowserTestUtils.removeTab(tab, { dontRemove: true });
+
+    yield ContentTask.spawn(browser, null, function*() {
+      let doc = content.document;
+      ok(!doc.documentElement.classList.contains("crashDumpAvailable"),
+         "doesn't have crash dump");
+
+      let container = doc.getElementById("crash-reporter-container");
+      ok(container, "has crash-reporter-container");
+      ok(container.hidden, "crash-reporter-container is hidden");
+
+      doc.getElementById("closeTab").click();
+    });
+
+    yield tabRemovedPromise;
+  });
+});
--- a/browser/base/content/test/general/browser_action_searchengine.js
+++ b/browser/base/content/test/general/browser_action_searchengine.js
@@ -30,17 +30,17 @@ add_task(function* () {
     return PlacesTestUtils.clearHistory();
   });
 
   yield promiseAutocompleteResultPopup("open a search");
   let result = gURLBar.popup.richlistbox.firstChild;
 
   isnot(result, null, "Should have a result");
   is(result.getAttribute("url"),
-     `moz-action:searchengine,{"engineName":"MozSearch","input":"open a search","searchQuery":"open a search"}`,
+     `moz-action:searchengine,{"engineName":"MozSearch","input":"open%20a%20search","searchQuery":"open%20a%20search"}`,
      "Result should be a moz-action: for the correct search engine");
   is(result.hasAttribute("image"), false, "Result shouldn't have an image attribute");
 
   let tabPromise = promiseTabLoaded(gBrowser.selectedTab);
   result.click();
   yield tabPromise;
 
   is(gBrowser.selectedBrowser.currentURI.spec, "http://example.com/?q=open+a+search", "Correct URL should be loaded");
--- a/browser/base/content/test/general/browser_audioTabIcon.js
+++ b/browser/base/content/test/general/browser_audioTabIcon.js
@@ -1,14 +1,15 @@
 const PAGE = "https://example.com/browser/browser/base/content/test/general/file_mediaPlayback.html";
 
 function* wait_for_tab_playing_event(tab, expectPlaying) {
   yield BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, (event) => {
     if (event.detail.changed.indexOf("soundplaying") >= 0) {
       is(tab.hasAttribute("soundplaying"), expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
+      is(tab.soundPlaying, expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
       return true;
     }
     return false;
   });
 }
 
 function* play(tab) {
   let browser = tab.linkedBrowser;
@@ -67,20 +68,32 @@ function* test_tooltip(icon, expectedToo
     isnot(tooltip.getAttribute("label"), expectedTooltip, "Tooltips should not be equal");
     is(tooltip.getAttribute("label").indexOf(expectedTooltip), 0, "Correct tooltip expected");
   } else {
     is(tooltip.getAttribute("label"), expectedTooltip, "Tooltips should not be equal");
   }
   leave_icon(icon);
 }
 
+// The set of tabs which have ever had their mute state changed.
+// Used to determine whether the tab should have a muteReason value.
+let everMutedTabs = new WeakSet();
+
 function get_wait_for_mute_promise(tab, expectMuted) {
   return BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, event => {
     if (event.detail.changed.indexOf("muted") >= 0) {
       is(tab.hasAttribute("muted"), expectMuted, "The tab should " + (expectMuted ? "" : "not ") + "be muted");
+      is(tab.muted, expectMuted, "The tab muted property " + (expectMuted ? "" : "not ") + "be true");
+