Merge m-c -> cedar
authorJonathan Griffin <jgriffin@mozilla.com>
Thu, 22 Jan 2015 16:04:11 -0800
changeset 326730 2dea8b3c6c91a5d1eee3ad5fffd6a3202ab59407
parent 326729 7b3268cab61b9c901b3e5079e0e5323f3439d460 (current diff)
parent 238496 43ad59d08bc4bf7c33bae4a24148e9d14fcd1a7c (diff)
child 326731 dd51b56ae609aad034220b1aaf9f1016a1b943f7
push id10169
push userdminor@mozilla.com
push dateThu, 28 Jan 2016 13:10:48 +0000
milestone38.0a1
Merge m-c -> cedar
dom/indexedDB/test/browser_quotaPrompt.html
dom/indexedDB/test/browser_quotaPromptAllow.js
dom/indexedDB/test/browser_quotaPromptDatabases.html
dom/indexedDB/test/browser_quotaPromptDatabases.js
dom/indexedDB/test/browser_quotaPromptDelete.html
dom/indexedDB/test/browser_quotaPromptDelete.js
dom/indexedDB/test/browser_quotaPromptDeny.js
dom/indexedDB/test/test_file_quota.html
dom/indexedDB/test/test_filehandle_quota.html
dom/media/tests/mochitest/test_getUserMedia_exceptions.html
dom/quota/CheckQuotaHelper.cpp
dom/quota/CheckQuotaHelper.h
mobile/android/base/SysInfo.java.in
mobile/android/base/background/common/GlobalConstants.java.in
mobile/android/base/background/healthreport/HealthReportConstants.java.in
mobile/android/base/fxa/FxAccountConstants.java.in
mobile/android/base/sync/SyncConstants.java.in
mobile/android/config/mozconfigs/android-api-10/debug
mobile/android/config/mozconfigs/android-api-10/l10n-nightly
mobile/android/config/mozconfigs/android-api-10/nightly
mobile/android/config/mozconfigs/android-api-9-constrained/debug
mobile/android/config/mozconfigs/android-api-9-constrained/l10n-nightly
mobile/android/config/mozconfigs/android-api-9-constrained/nightly
security/sandbox/build/build_config.h
security/sandbox/chromium-commit-status.txt
security/sandbox/chromium/base/shim/base/gtest_prod_util.h
security/sandbox/chromium/base/shim/base/logging.cpp
security/sandbox/chromium/base/shim/base/strings/string_piece.h
security/sandbox/chromium/base/shim/base/third_party/nspr/prtime.h
security/sandbox/chromium/base/shim/base/third_party/nspr/prtypes.h
security/sandbox/chromium/base/shim/base/threading/thread_local_storage.h
security/sandbox/chromium/base/shim/base/tracked_objects.h
security/sandbox/chromium/base/shim/base/win/registry.h
security/sandbox/chromium/base/shim/sdkdecls.h
security/sandbox/win/src/LICENSE
security/sandbox/win/src/Wow64.cc
security/sandbox/win/src/Wow64.h
security/sandbox/win/src/Wow64_64.cc
security/sandbox/win/src/acl.cc
security/sandbox/win/src/acl.h
security/sandbox/win/src/app_container.cc
security/sandbox/win/src/app_container.h
security/sandbox/win/src/app_container_test.cc
security/sandbox/win/src/app_container_unittest.cc
security/sandbox/win/src/broker_services.cc
security/sandbox/win/src/broker_services.h
security/sandbox/win/src/crosscall_client.h
security/sandbox/win/src/crosscall_params.h
security/sandbox/win/src/crosscall_server.cc
security/sandbox/win/src/crosscall_server.h
security/sandbox/win/src/eat_resolver.cc
security/sandbox/win/src/eat_resolver.h
security/sandbox/win/src/file_policy_test.cc
security/sandbox/win/src/filesystem_dispatcher.cc
security/sandbox/win/src/filesystem_dispatcher.h
security/sandbox/win/src/filesystem_interception.cc
security/sandbox/win/src/filesystem_interception.h
security/sandbox/win/src/filesystem_policy.cc
security/sandbox/win/src/filesystem_policy.h
security/sandbox/win/src/handle_closer.cc
security/sandbox/win/src/handle_closer.h
security/sandbox/win/src/handle_closer_agent.cc
security/sandbox/win/src/handle_closer_agent.h
security/sandbox/win/src/handle_closer_test.cc
security/sandbox/win/src/handle_dispatcher.cc
security/sandbox/win/src/handle_dispatcher.h
security/sandbox/win/src/handle_inheritance_test.cc
security/sandbox/win/src/handle_interception.cc
security/sandbox/win/src/handle_interception.h
security/sandbox/win/src/handle_policy.cc
security/sandbox/win/src/handle_policy.h
security/sandbox/win/src/handle_policy_test.cc
security/sandbox/win/src/handle_table.cc
security/sandbox/win/src/handle_table.h
security/sandbox/win/src/integrity_level_test.cc
security/sandbox/win/src/interception.cc
security/sandbox/win/src/interception.h
security/sandbox/win/src/interception_agent.cc
security/sandbox/win/src/interception_agent.h
security/sandbox/win/src/interception_internal.h
security/sandbox/win/src/interception_unittest.cc
security/sandbox/win/src/interceptors.h
security/sandbox/win/src/interceptors_64.cc
security/sandbox/win/src/interceptors_64.h
security/sandbox/win/src/internal_types.h
security/sandbox/win/src/ipc_ping_test.cc
security/sandbox/win/src/ipc_tags.h
security/sandbox/win/src/ipc_unittest.cc
security/sandbox/win/src/job.cc
security/sandbox/win/src/job.h
security/sandbox/win/src/job_unittest.cc
security/sandbox/win/src/logging/loggingCallbacks.h
security/sandbox/win/src/logging/loggingTypes.h
security/sandbox/win/src/logging/sandboxLogging.cpp
security/sandbox/win/src/logging/sandboxLogging.h
security/sandbox/win/src/named_pipe_dispatcher.cc
security/sandbox/win/src/named_pipe_dispatcher.h
security/sandbox/win/src/named_pipe_interception.cc
security/sandbox/win/src/named_pipe_interception.h
security/sandbox/win/src/named_pipe_policy.cc
security/sandbox/win/src/named_pipe_policy.h
security/sandbox/win/src/named_pipe_policy_test.cc
security/sandbox/win/src/nt_internals.h
security/sandbox/win/src/policy_broker.cc
security/sandbox/win/src/policy_broker.h
security/sandbox/win/src/policy_engine_opcodes.cc
security/sandbox/win/src/policy_engine_opcodes.h
security/sandbox/win/src/policy_engine_params.h
security/sandbox/win/src/policy_engine_processor.cc
security/sandbox/win/src/policy_engine_processor.h
security/sandbox/win/src/policy_engine_unittest.cc
security/sandbox/win/src/policy_low_level.cc
security/sandbox/win/src/policy_low_level.h
security/sandbox/win/src/policy_low_level_unittest.cc
security/sandbox/win/src/policy_opcodes_unittest.cc
security/sandbox/win/src/policy_params.h
security/sandbox/win/src/policy_target.cc
security/sandbox/win/src/policy_target.h
security/sandbox/win/src/policy_target_test.cc
security/sandbox/win/src/process_mitigations.cc
security/sandbox/win/src/process_mitigations.h
security/sandbox/win/src/process_mitigations_test.cc
security/sandbox/win/src/process_mitigations_win32k_dispatcher.cc
security/sandbox/win/src/process_mitigations_win32k_dispatcher.h
security/sandbox/win/src/process_mitigations_win32k_interception.cc
security/sandbox/win/src/process_mitigations_win32k_interception.h
security/sandbox/win/src/process_mitigations_win32k_policy.cc
security/sandbox/win/src/process_mitigations_win32k_policy.h
security/sandbox/win/src/process_policy_test.cc
security/sandbox/win/src/process_thread_dispatcher.cc
security/sandbox/win/src/process_thread_dispatcher.h
security/sandbox/win/src/process_thread_interception.cc
security/sandbox/win/src/process_thread_interception.h
security/sandbox/win/src/process_thread_policy.cc
security/sandbox/win/src/process_thread_policy.h
security/sandbox/win/src/registry_dispatcher.cc
security/sandbox/win/src/registry_dispatcher.h
security/sandbox/win/src/registry_interception.cc
security/sandbox/win/src/registry_interception.h
security/sandbox/win/src/registry_policy.cc
security/sandbox/win/src/registry_policy.h
security/sandbox/win/src/registry_policy_test.cc
security/sandbox/win/src/resolver.cc
security/sandbox/win/src/resolver.h
security/sandbox/win/src/resolver_32.cc
security/sandbox/win/src/resolver_64.cc
security/sandbox/win/src/restricted_token.cc
security/sandbox/win/src/restricted_token.h
security/sandbox/win/src/restricted_token_unittest.cc
security/sandbox/win/src/restricted_token_utils.cc
security/sandbox/win/src/restricted_token_utils.h
security/sandbox/win/src/sandbox.cc
security/sandbox/win/src/sandbox.h
security/sandbox/win/src/sandbox.vcproj
security/sandbox/win/src/sandbox_factory.h
security/sandbox/win/src/sandbox_globals.cc
security/sandbox/win/src/sandbox_nt_types.h
security/sandbox/win/src/sandbox_nt_util.cc
security/sandbox/win/src/sandbox_nt_util.h
security/sandbox/win/src/sandbox_policy.h
security/sandbox/win/src/sandbox_policy_base.cc
security/sandbox/win/src/sandbox_policy_base.h
security/sandbox/win/src/sandbox_types.h
security/sandbox/win/src/sandbox_utils.cc
security/sandbox/win/src/sandbox_utils.h
security/sandbox/win/src/security_level.h
security/sandbox/win/src/service_resolver.cc
security/sandbox/win/src/service_resolver.h
security/sandbox/win/src/service_resolver_32.cc
security/sandbox/win/src/service_resolver_64.cc
security/sandbox/win/src/service_resolver_unittest.cc
security/sandbox/win/src/shared_handles.cc
security/sandbox/win/src/shared_handles.h
security/sandbox/win/src/sharedmem_ipc_client.cc
security/sandbox/win/src/sharedmem_ipc_client.h
security/sandbox/win/src/sharedmem_ipc_server.cc
security/sandbox/win/src/sharedmem_ipc_server.h
security/sandbox/win/src/sid.cc
security/sandbox/win/src/sid.h
security/sandbox/win/src/sid_unittest.cc
security/sandbox/win/src/sidestep/ia32_modrm_map.cpp
security/sandbox/win/src/sidestep/ia32_opcode_map.cpp
security/sandbox/win/src/sidestep/mini_disassembler.cpp
security/sandbox/win/src/sidestep/mini_disassembler.h
security/sandbox/win/src/sidestep/mini_disassembler_types.h
security/sandbox/win/src/sidestep/preamble_patcher.h
security/sandbox/win/src/sidestep/preamble_patcher_with_stub.cpp
security/sandbox/win/src/sidestep_resolver.cc
security/sandbox/win/src/sidestep_resolver.h
security/sandbox/win/src/sync_dispatcher.cc
security/sandbox/win/src/sync_dispatcher.h
security/sandbox/win/src/sync_interception.cc
security/sandbox/win/src/sync_interception.h
security/sandbox/win/src/sync_policy.cc
security/sandbox/win/src/sync_policy.h
security/sandbox/win/src/sync_policy_test.cc
security/sandbox/win/src/sync_policy_test.h
security/sandbox/win/src/target_interceptions.cc
security/sandbox/win/src/target_interceptions.h
security/sandbox/win/src/target_process.cc
security/sandbox/win/src/target_process.h
security/sandbox/win/src/target_services.cc
security/sandbox/win/src/target_services.h
security/sandbox/win/src/threadpool_unittest.cc
security/sandbox/win/src/unload_dll_test.cc
security/sandbox/win/src/win2k_threadpool.cc
security/sandbox/win/src/win2k_threadpool.h
security/sandbox/win/src/win_utils.cc
security/sandbox/win/src/win_utils.h
security/sandbox/win/src/win_utils_unittest.cc
security/sandbox/win/src/window.cc
security/sandbox/win/src/window.h
testing/web-platform/harness/wptrunner/browsers/firefox.py
testing/web-platform/meta/FileAPI/Blob-constructor.html.ini
testing/web-platform/meta/media-source/mediasource-config-change-webm-av-framesize.html.ini
testing/web-platform/meta/media-source/mediasource-config-change-webm-v-framesize.html.ini
testing/web-platform/meta/selectors-api/tests/submissions/Opera/ParentNode-find-findAll.html.ini
testing/web-platform/tests/XMLHttpRequest/withcredentials-set.htm
testing/web-platform/tests/XMLHttpRequest/withcredentials-wrong-state.htm
testing/web-platform/tests/selectors-api/tests/submissions/Opera/Element-matches.html
testing/web-platform/tests/selectors-api/tests/submissions/Opera/ParentNode-find-findAll.html
testing/web-platform/tests/selectors-api/tests/submissions/Opera/ParentNode-find-findAll.js
testing/web-platform/tests/selectors-api/tests/submissions/Opera/level2-lib.js
testing/web-platform/tests/workers/WorkerGlobalScope_EventTarget.htm
testing/web-platform/tests/workers/WorkerGlobalScope_XMLHttpRequest.htm
testing/web-platform/tests/workers/WorkerGlobalScope_addEventListener.htm
testing/web-platform/tests/workers/WorkerGlobalScope_nested_Worker.htm
testing/web-platform/tests/workers/WorkerGlobalScope_removeEventListener.htm
toolkit/components/places/tests/expiration/test_removeAllPages.js
toolkit/components/places/tests/unit/test_history_removeAllPages.js
xpcom/tests/TestPipes.cpp
xpcom/tests/TestPriorityQueue.cpp
xpcom/tests/TestStorageStream.cpp
xpcom/tests/TestSynchronization.cpp
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,10 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1100184 - Lots of file moves from the /netwerk flattening and zero faith
-in the build system to properly handle them.
+Bugs 1101331 - See if a CLOBBER helps the situation any.
--- a/accessible/base/RelationType.h
+++ b/accessible/base/RelationType.h
@@ -7,17 +7,17 @@
 #ifndef mozilla_a11y_relationtype_h_
 #define mozilla_a11y_relationtype_h_
 
 #include "mozilla/TypedEnum.h"
 
 namespace mozilla {
 namespace a11y {
 
-MOZ_BEGIN_ENUM_CLASS(RelationType)
+enum class RelationType {
 
   /**
    * This object is labelled by a target object.
    */
   LABELLED_BY = 0x00,
 
   /**
    * This object is label for a target object.
@@ -126,14 +126,14 @@ MOZ_BEGIN_ENUM_CLASS(RelationType)
 
   /**
    * The target object is the containing application object.
    */
   CONTAINING_APPLICATION = 0x14,
 
   LAST = CONTAINING_APPLICATION
 
-MOZ_END_ENUM_CLASS(RelationType)
+};
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -296,19 +296,16 @@ pref("dom.ipc.tabs.disabled", false);
 pref("layers.acceleration.disabled", false);
 pref("layers.async-pan-zoom.enabled", true);
 pref("gfx.content.azure.backends", "cairo");
 #endif
 
 // Web Notifications
 pref("notification.feature.enabled", true);
 
-// IndexedDB
-pref("dom.indexedDB.warningQuota", 5);
-
 // prevent video elements from preloading too much data
 pref("media.preload.default", 1); // default to preload none
 pref("media.preload.auto", 2);    // preload metadata if preload=auto
 pref("media.cache_size", 4096);    // 4MB media cache
 // Try to save battery by not resuming reading from a connection until we fall
 // below 10s of buffered data.
 pref("media.cache_resume_threshold", 10);
 pref("media.cache_readahead_limit", 30);
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -333,17 +333,16 @@ var shell = {
     this.contentBrowser.addEventListener('mozbrowserloadstart', this, true);
     this.contentBrowser.addEventListener('mozbrowserselectionstatechanged', this, true);
     this.contentBrowser.addEventListener('mozbrowserscrollviewchange', this, true);
     this.contentBrowser.addEventListener('mozbrowsertouchcarettap', this, true);
 
     CustomEventManager.init();
     WebappsHelper.init();
     UserAgentOverrides.init();
-    IndexedDBPromptHelper.init();
     CaptivePortalLoginHelper.init();
 
     this.contentBrowser.src = homeURL;
     this.isHomeLoaded = false;
 
     ppmm.addMessageListener("content-handler", this);
     ppmm.addMessageListener("dial-handler", this);
     ppmm.addMessageListener("sms-handler", this);
@@ -360,17 +359,16 @@ var shell = {
     window.removeEventListener('sizemodechange', this);
     this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true);
     this.contentBrowser.removeEventListener('mozbrowserselectionstatechanged', this, true);
     this.contentBrowser.removeEventListener('mozbrowserscrollviewchange', this, true);
     this.contentBrowser.removeEventListener('mozbrowsertouchcarettap', this, true);
     ppmm.removeMessageListener("content-handler", this);
 
     UserAgentOverrides.uninit();
-    IndexedDBPromptHelper.uninit();
   },
 
   // If this key event represents a hardware button which needs to be send as
   // a message, broadcasts it with the message set to 'xxx-button-press' or
   // 'xxx-button-release'.
   broadcastHardwareKeys: function shell_broadcastHardwareKeys(evt) {
     let type;
     let message;
@@ -790,47 +788,16 @@ var WebappsHelper = {
         shell.sendCustomEvent("webapps-close", {
           "manifestURL": json.manifestURL
         });
         break;
     }
   }
 }
 
-let IndexedDBPromptHelper = {
-  _quotaPrompt: "indexedDB-quota-prompt",
-  _quotaResponse: "indexedDB-quota-response",
-
-  init:
-  function IndexedDBPromptHelper_init() {
-    Services.obs.addObserver(this, this._quotaPrompt, false);
-  },
-
-  uninit:
-  function IndexedDBPromptHelper_uninit() {
-    Services.obs.removeObserver(this, this._quotaPrompt);
-  },
-
-  observe:
-  function IndexedDBPromptHelper_observe(subject, topic, data) {
-    if (topic != this._quotaPrompt) {
-      throw new Error("Unexpected topic!");
-    }
-
-    let observer = subject.QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIObserver);
-    let responseTopic = this._quotaResponse;
-
-    setTimeout(function() {
-      observer.observe(null, responseTopic,
-                       Ci.nsIPermissionManager.DENY_ACTION);
-    }, 0);
-  }
-}
-
 let KeyboardHelper = {
   handleEvent: function keyboard_handleEvent(detail) {
     switch (detail.type) {
       case 'inputmethod-update-layouts':
         Keyboard.setLayouts(detail.layouts);
 
         break;
       case 'inputregistry-add':
new file mode 100644
--- /dev/null
+++ b/b2g/config/dolphin-512/config.json
@@ -0,0 +1,42 @@
+{
+    "config_version": 2,
+    "mock_target": "mozilla-centos6-x86_64",
+    "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel", "git", "libxml2", "bc"],
+    "mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
+    "build_targets": ["kernelheader", ""],
+    "upload_files": [
+        "{objdir}/dist/b2g-*.crashreporter-symbols.zip",
+        "{objdir}/dist/b2g-*.tar.gz",
+        "{workdir}/sources.xml"
+    ],
+    "public_upload_files": [
+        "{objdir}/dist/b2g-*.crashreporter-symbols.zip",
+        "{objdir}/dist/b2g-*.tar.gz",
+        "{workdir}/sources.xml"
+    ],
+    "zip_files": [
+        ["{workdir}/out/target/product/scx15_sp7715ea/*.img", "out/target/product/scx15_sp7715ea/"],
+        "{workdir}/flash.sh",
+        "{workdir}/load-config.sh",
+        "{workdir}/.config",
+        "{workdir}/sources.xml",
+        "{workdir}/profile.sh",
+        ["{workdir}/gecko/tools/profiler/merge-profiles.py", "gecko/tools/profiler/"],
+        ["{workdir}/scripts/profile-symbolicate.py", "scripts/"],
+        ["{workdir}/gecko/tools/rb/fix_stack_using_bpsyms.py", "gecko/tools/rb/"]
+    ],
+    "env": {
+        "VARIANT": "user",
+        "MOZILLA_OFFICIAL": "1"
+    },
+    "b2g_manifest": "dolphin-512.xml",
+    "b2g_manifest_intree": true,
+    "additional_source_tarballs": [],
+    "gecko_l10n_root": "https://hg.mozilla.org/l10n-central",
+    "gaia": {
+        "l10n": {
+            "vcs": "hgtool",
+            "root": "https://hg.mozilla.org/gaia-l10n"
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/b2g/config/dolphin-512/sources.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
+  <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
+  <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
+  <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was git://github.com/apitrace/-->
+  <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
+  <!--original fetch url was git://codeaurora.org/-->
+  <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
+  <!--original fetch url was https://git.mozilla.org/releases-->
+  <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
+  <!-- B2G specific things. -->
+  <project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
+    <copyfile dest="Makefile" src="core/root.mk"/>
+  </project>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="9946a490a9264b42e65385d703b28fa055ab2d42"/>
+  <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="049c281ad212bf528b2af8fc246b0dd0c9f97415"/>
+  <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
+  <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
+  <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
+  <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
+  <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
+  <!-- Stock Android things -->
+  <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
+  <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
+  <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
+  <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
+  <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
+  <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
+  <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
+  <project name="device/sample" path="device/sample" revision="1a3d8efa0ad32ec8f145367a3cf0f54b97385c3c"/>
+  <project name="platform/abi/cpp" path="abi/cpp" revision="18f1b5e28734183ff8073fe86dc46bc4ebba8a59"/>
+  <project name="platform/bionic" path="bionic" revision="86b1f589c313422a7da1812512b9ec8d1cf9ba3c"/>
+  <project name="platform/bootable/recovery" path="bootable/recovery" revision="75a2463ff719f242759de5c6c7555473dab05b68"/>
+  <project name="platform/external/aac" path="external/aac" revision="fa3eba16446cc8f2f5e2dfc20d86a49dbd37299e"/>
+  <project name="platform/external/bison" path="external/bison" revision="c2418b886165add7f5a31fc5609f0ce2d004a90e"/>
+  <project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="c8e99ca7e11c00f8124196fe1726a15e6e976587"/>
+  <project name="platform/external/bsdiff" path="external/bsdiff" revision="23e322ab19fb7d74c2c37e40ce364d9f709bdcee"/>
+  <project name="platform/external/bzip2" path="external/bzip2" revision="1cb636bd8e9e5cdfd5d5b2909a122f6e80db62de"/>
+  <project name="platform/external/checkpolicy" path="external/checkpolicy" revision="0d73ef7049feee794f14cf1af88d05dae8139914"/>
+  <project name="platform/external/dhcpcd" path="external/dhcpcd" revision="84b7252b0a9d0edc9a1db1e0c518771d26b23058"/>
+  <project name="platform/external/dnsmasq" path="external/dnsmasq" revision="41d356427a632f5336384bfa45c8420ffc274f66"/>
+  <project name="platform/external/dropbear" path="external/dropbear" revision="a34ddbe3819bc465968f3676c734b405e655f8b7"/>
+  <project name="platform/external/e2fsprogs" path="external/e2fsprogs" revision="47478a2944a2a17c7fdebe9d92573db92013125c"/>
+  <project name="platform/external/elfutils" path="external/elfutils" revision="b23b2dfb354b3ccf5d1c5d39815f02e7048cf516"/>
+  <project name="platform/external/expat" path="external/expat" revision="0af0cb3bc7519e567bd9daff3dcd315ab0134a99"/>
+  <project name="platform/external/fdlibm" path="external/fdlibm" revision="0da5f683c9ddc9442af3b389b4220e91ccffb320"/>
+  <project name="platform/external/flac" path="external/flac" revision="ab37b6247df0e8c4ec0ccaa870e667f62c74975b"/>
+  <project name="platform/external/freetype" path="external/freetype" revision="899c67b6cfcd2010784fbf08c5415af16c526e0c"/>
+  <project name="platform/external/gcc-demangle" path="external/gcc-demangle" revision="9241386b62c353302c2f9eccda0672685b252b4d"/>
+  <project name="platform/external/genext2fs" path="external/genext2fs" revision="e11a9c7fe6f1cef99aad2f25afaea37b72fe9f93"/>
+  <project name="platform/external/giflib" path="external/giflib" revision="9aef3ea079a57c98a9207f8c3b95a5dc08ee74b5"/>
+  <project name="platform/external/gtest" path="external/gtest" revision="0f1ce3dd0b880b6ae0cf7f5413702b8ef542efb2"/>
+  <project name="platform/external/harfbuzz" path="external/harfbuzz" revision="858f2d28ac741ef139f74bdbdbcefa7560f17c91"/>
+  <project name="platform/external/harfbuzz_ng" path="external/harfbuzz_ng" revision="3309edccdbc2a92eb03a285abb27c1c1c4a88e43"/>
+  <project name="platform/external/iproute2" path="external/iproute2" revision="157d428913c3d738be481f12e8cbf9267b3b2862"/>
+  <project name="platform/external/ipsec-tools" path="external/ipsec-tools" revision="f4cb1ee4b00abbfb6f968dc25818c23b4b47e584"/>
+  <project name="platform/external/iptables" path="external/iptables" revision="93e814c9b08136846335ce463192d90ba59766bb"/>
+  <project name="platform/external/jack" path="external/jack" revision="5ceb2025ac5d25ed48183ac2d3dac4691fe761fb"/>
+  <project name="platform/external/jhead" path="external/jhead" revision="31b17e69a87e4caa50f9c6b1a47c84ef75f79d83"/>
+  <project name="platform/external/jpeg" path="external/jpeg" revision="68f6f73d3157cc0481826e03d0fae9586217a300"/>
+  <project name="platform/external/junit" path="external/junit" revision="3abf41974d8aae44b3bbd15d83487894253d287d"/>
+  <project name="platform/external/libgsm" path="external/libgsm" revision="50761abed8f4734970874165b386cfd4d9599db4"/>
+  <project name="platform/external/liblzf" path="external/liblzf" revision="6946aa575b0949d045722794850896099d937cbb"/>
+  <project name="platform/external/libnfc-nxp" path="external/libnfc-nxp" revision="9e987ccb716624d658f98abc7db2097e11e3d8ed"/>
+  <project name="platform/external/libnl-headers" path="external/libnl-headers" revision="6ccf7349d61f73ac26a0675d735d903ab919c658"/>
+  <project name="platform/external/libogg" path="external/libogg" revision="ec0b24fb1468abe37be4164a6feb16568e036bde"/>
+  <project name="platform/external/libpcap" path="external/libpcap" revision="3a7bce5dda6a8db92c9248846d0255e68c3a5b2a"/>
+  <project name="platform/external/libpng" path="external/libpng" revision="b5e7fb4c103b3898cb78e9f7615cf7893626a5e9"/>
+  <project name="platform/external/libselinux" path="external/libselinux" revision="1e2cf2c4a2d15a9b1ca2d353b99fb6884413ffe1"/>
+  <project name="platform/external/libsepol" path="external/libsepol" revision="8fd7c65a336d45d5225f32363a9f26c1e3e60c3c"/>
+  <project name="platform/external/libvpx" path="external/libvpx" revision="5e563eddf3e143a4b670766b49f676ce39023322"/>
+  <project name="platform/external/mdnsresponder" path="external/mdnsresponder" revision="c46f53f5e072f23051c4eedef730386f7634dc11"/>
+  <project name="platform/external/mksh" path="external/mksh" revision="f8c396c4d446a038358106a301b329607a04633d"/>
+  <project name="platform/external/netcat" path="external/netcat" revision="444644cfa9a2f3002863caa168fb2d6b34dfd1e8"/>
+  <project name="platform/external/netperf" path="external/netperf" revision="58ecd3b7c76263900e38921360e334a416aec362"/>
+  <project name="platform/external/openssl" path="external/openssl" revision="bb8428f762b3632f493572c4f73957e1281ade79"/>
+  <project name="platform/external/protobuf" path="external/protobuf" revision="48ee66d295979372ed0234cefda42385daae8312"/>
+  <project name="platform/external/safe-iop" path="external/safe-iop" revision="aa0725fb1da35e47676b6da30009322eb5ed59be"/>
+  <project name="platform/external/scrypt" path="external/scrypt" revision="eb05b73c3bba21fff55529813109de4bad5ddbd1"/>
+  <project name="platform/external/sepolicy" path="external/sepolicy" revision="f3525622103090156a6bbd9a8609be8b009d223f"/>
+  <project name="platform/external/sfntly" path="external/sfntly" revision="30d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cd"/>
+  <project name="platform/external/skia" path="external/skia" revision="97c714a01e32e6aee7faf9c57fbbd4d95b41d353"/>
+  <project name="platform/external/sonivox" path="external/sonivox" revision="2dbbd3bac0f0e819d196a80cc7855054148ef8b6"/>
+  <project name="platform/external/speex" path="external/speex" revision="fb7db5853ffb841a4d32fea8b5c3a43e6b875cae"/>
+  <project name="platform/external/sqlite" path="external/sqlite" revision="ac0e0d5f866fbce0ebf00d0ddd615464849aa83b"/>
+  <project name="platform/external/stlport" path="external/stlport" revision="628e14d37c5b239839a466e81c74bf66255b770b"/>
+  <project name="platform/external/strace" path="external/strace" revision="1a4e05d53dec658a061acb9869cb1eb1342cd09d"/>
+  <project name="platform/external/svox" path="external/svox" revision="838228cc17b5798e51bc20d06e54dbd781e441db"/>
+  <project name="platform/external/tagsoup" path="external/tagsoup" revision="68c2ec9e0acdb3214b7fb91dbab8c9fab8736817"/>
+  <project name="platform/external/tcpdump" path="external/tcpdump" revision="532b8f38c144da9a298260a5d8978ab9e8e3856c"/>
+  <project name="platform/external/tinyalsa" path="external/tinyalsa" revision="aa08b9c35638a32de0444a940cf47708e4ba0eda"/>
+  <project name="platform/external/tinycompress" path="external/tinycompress" revision="a85e245a09c028d36cbf04f233be10bc583691f5"/>
+  <project name="platform/external/tinyxml" path="external/tinyxml" revision="494e448824844d866e805831d1d5f5acb654065c"/>
+  <project name="platform/external/tinyxml2" path="external/tinyxml2" revision="c74b546f5af36968ffa56d7fd4529f4273b96f48"/>
+  <project name="platform/external/tremolo" path="external/tremolo" revision="0499204aa97d3e2978ee77d869dd033acb2196e2"/>
+  <project name="platform/external/webp" path="external/webp" revision="513e97bd307573e2adc776eb5368bd129aceaa4a"/>
+  <project name="platform/external/webrtc" path="external/webrtc" revision="446452f84e9cc4c75d8e80f6f05e24793397a19d"/>
+  <project name="platform/external/yaffs2" path="external/yaffs2" revision="a2cff2275e1b501ff478b03757d6e4f05fddc2db"/>
+  <project name="platform/external/zlib" path="external/zlib" revision="a5c7131da47c991585a6c6ac0c063b6d7d56e3fc"/>
+  <project name="platform/frameworks/base" path="frameworks/base" revision="2d12cb68a6c680e1ef50c6fbd19f782f67aec9de"/>
+  <project name="platform/frameworks/native" path="frameworks/native" revision="b6018ccb81af66e0523a4bfdc45f0bd2ab472b55"/>
+  <project name="platform/frameworks/opt/emoji" path="frameworks/opt/emoji" revision="dbbe673145107e99883f62bafd70c5f43f11065c"/>
+  <project name="platform/frameworks/wilhelm" path="frameworks/wilhelm" revision="aac6c4bb59a6577c97cbda68699829b507b7490d"/>
+  <project name="platform/hardware/libhardware" path="hardware/libhardware" revision="fbeca55f4695dd07c0291213403533b8fbca4885"/>
+  <project name="platform/hardware/libhardware_legacy" path="hardware/libhardware_legacy" revision="a8449b1de00c313a4ca90d55af44c9b706b17926"/>
+  <project name="platform/libcore" path="libcore" revision="e195beab082c09217318fc19250caeaf4c1bd800"/>
+  <project name="platform/libnativehelper" path="libnativehelper" revision="feeb36c2bd4adfe285f98f5de92e0f3771b2c115"/>
+  <project name="platform/ndk" path="ndk" revision="e58ef003be4306bb53a8c11331146f39e4eab31f"/>
+  <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="0e7c060db684b409616fe67ea433ef19f5634c60"/>
+  <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="c792f0bd9fff7aea2887c60bbb3a9bbdb534ffa3"/>
+  <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="f7d9bf71cf6693474f3f2a81a4ba62c0fc5646aa"/>
+  <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="cfcef469537869947abb9aa1d656774cc2678d4c"/>
+  <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="288db53ad77084bd44791add5e3a4c266a6e9c60"/>
+  <project name="platform/system/extras" path="system/extras" revision="10e78a05252b3de785f88c2d0b9ea8a428009c50"/>
+  <project name="platform/system/media" path="system/media" revision="7ff72c2ea2496fa50b5e8a915e56e901c3ccd240"/>
+  <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="fe95bc6f83af5c18a73aa86c96e7fa7f79b91477"/>
+  <project name="platform/system/netd" path="system/netd" revision="3ae56364946d4a5bf5a5f83f12f9a45a30398e33"/>
+  <project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>
+  <project name="platform/system/vold" path="system/vold" revision="2e43efe1b30d0b98574d293059556aebd2f46454"/>
+  <!--original fetch url was http://sprdsource.spreadtrum.com:8085/b2g/android-->
+  <remote fetch="https://git.mozilla.org/external/sprd-aosp" name="sprd-aosp"/>
+  <default remote="sprd-aosp" revision="sprdb2g_gonk4.4" sync-j="4"/>
+  <!-- Stock Android things -->
+  <project name="platform/external/icu4c" path="external/icu4c" revision="2bb01561780583cc37bc667f0ea79f48a122d8a2"/>
+  <!-- dolphin specific things -->
+  <project name="device/sprd" path="device/sprd" revision="b94ac10f073ed2503505e59f5097d4e286423037"/>
+  <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="4e58336019b5cbcfd134caf55b142236cf986618"/>
+  <project name="platform/frameworks/av" path="frameworks/av" revision="4387fe988e5a1001f29ce05fcfda03ed2d32137b"/>
+  <project name="platform/hardware/akm" path="hardware/akm" revision="6d3be412647b0eab0adff8a2768736cf4eb68039"/>
+  <project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/>
+  <project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/>
+  <project name="kernel/common" path="kernel" revision="6c6f012cea17fb8b3263605737816cf6663432f1"/>
+  <project name="platform/system/core" path="system/core" revision="53d584d4a4b4316e4de9ee5f210d662f89b44e7e"/>
+  <project name="u-boot" path="u-boot" revision="5167e5eec5cb6b3147839da158637e6d953a4e4f"/>
+  <project name="vendor/sprd/gps" path="vendor/sprd/gps" revision="6974f8e771d4d8e910357a6739ab124768891e8f"/>
+  <project name="vendor/sprd/open-source" path="vendor/sprd/open-source" revision="a6f913f0e114945d995680a6fe5cccb24c02b3c2"/>
+  <project name="vendor/sprd/partner" path="vendor/sprd/partner" revision="8649c7145972251af11b0639997edfecabfc7c2e"/>
+  <project name="vendor/sprd/proprietories" path="vendor/sprd/proprietories" revision="d2466593022f7078aaaf69026adf3367c2adb7bb"/>
+</manifest>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="cba2f0bf49b882e0044c3cc583de8fcf83d2ffa4"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
@@ -111,17 +111,17 @@
   <project name="platform/libcore" path="libcore" revision="e195beab082c09217318fc19250caeaf4c1bd800"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="feeb36c2bd4adfe285f98f5de92e0f3771b2c115"/>
   <project name="platform/ndk" path="ndk" revision="e58ef003be4306bb53a8c11331146f39e4eab31f"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="0e7c060db684b409616fe67ea433ef19f5634c60"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="c792f0bd9fff7aea2887c60bbb3a9bbdb534ffa3"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="f7d9bf71cf6693474f3f2a81a4ba62c0fc5646aa"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="cfcef469537869947abb9aa1d656774cc2678d4c"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="8a05fd72770a3b1fc23f3216a45318ad393fc4ca"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="d8040bc7850e326b297045ccbd51bfd7bf566a53"/>
   <project name="platform/system/extras" path="system/extras" revision="10e78a05252b3de785f88c2d0b9ea8a428009c50"/>
   <project name="platform/system/media" path="system/media" revision="7ff72c2ea2496fa50b5e8a915e56e901c3ccd240"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="fe95bc6f83af5c18a73aa86c96e7fa7f79b91477"/>
   <project name="platform/system/netd" path="system/netd" revision="3ae56364946d4a5bf5a5f83f12f9a45a30398e33"/>
   <project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>
   <project name="platform/system/vold" path="system/vold" revision="2e43efe1b30d0b98574d293059556aebd2f46454"/>
   <!--original fetch url was http://sprdsource.spreadtrum.com:8085/b2g/android-->
   <remote fetch="https://git.mozilla.org/external/sprd-aosp" name="sprd-aosp"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cba2f0bf49b882e0044c3cc583de8fcf83d2ffa4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="cba2f0bf49b882e0044c3cc583de8fcf83d2ffa4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
@@ -113,17 +113,17 @@
   <project name="platform/libnativehelper" path="libnativehelper" revision="4792069e90385889b0638e97ae62c67cdf274e22"/>
   <project name="platform/ndk" path="ndk" revision="7666b97bbaf1d645cdd6b4430a367b7a2bb53369"/>
   <project name="platform/prebuilts/misc" path="prebuilts/misc" revision="f6ab40b3257abc07741188fd173ac392575cc8d2"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="e52099755d0bd3a579130eefe8e58066cc6c0cb6"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="02c32feb2fe97037be0ac4dace3a6a5025ac895d"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="8a05fd72770a3b1fc23f3216a45318ad393fc4ca"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="d8040bc7850e326b297045ccbd51bfd7bf566a53"/>
   <project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
   <project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="fe95bc6f83af5c18a73aa86c96e7fa7f79b91477"/>
   <project name="platform/system/media" path="system/media" revision="d90b836f66bf1d9627886c96f3a2d9c3007fbb80"/>
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="cba2f0bf49b882e0044c3cc583de8fcf83d2ffa4"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
@@ -111,17 +111,17 @@
   <project name="platform/libcore" path="libcore" revision="9877ade9617bb0db6e59aa2a54719a9bc92600f3"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="46c96ace65eb1ccab05bf15b9bf8e53e443039af"/>
   <project name="platform/ndk" path="ndk" revision="cb5519af32ae7b4a9c334913a612462ecd04c5d0"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="0e7c060db684b409616fe67ea433ef19f5634c60"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="6aa61f8557a22039a30b42b7f283996381fd625d"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="f7d9bf71cf6693474f3f2a81a4ba62c0fc5646aa"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="b562b01c93de9578d5db537b6a602a38e1aaa0ce"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="387f03e815f57d536dd922706db1622bddba8d81"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="8a05fd72770a3b1fc23f3216a45318ad393fc4ca"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="d8040bc7850e326b297045ccbd51bfd7bf566a53"/>
   <project name="platform/system/extras" path="system/extras" revision="5356165f67f4a81c2ef28671c13697f1657590df"/>
   <project name="platform/system/media" path="system/media" revision="be0e2fe59a8043fa5200f75697df9220a99abe9d"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="fe95bc6f83af5c18a73aa86c96e7fa7f79b91477"/>
   <project name="platform/system/netd" path="system/netd" revision="36704b0da24debcab8090156568ac236315036bb"/>
   <project name="platform/system/security" path="system/security" revision="583374f69f531ba68fc3dcbff1f74893d2a96406"/>
   <project name="platform/system/vold" path="system/vold" revision="d4455b8cf361f8353e8aebac15ffd64b4aedd2b9"/>
   <project name="platform/external/icu4c" path="external/icu4c" remote="aosp" revision="b4c6379528887dc25ca9991a535a8d92a61ad6b6"/>
   <project name="platform_frameworks_av" path="frameworks/av" remote="b2g" revision="f3cedd7fd9b1649aa5107d466be9078bb7602af6"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cba2f0bf49b882e0044c3cc583de8fcf83d2ffa4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="cba2f0bf49b882e0044c3cc583de8fcf83d2ffa4"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
@@ -106,17 +106,17 @@
   <project name="platform/libcore" path="libcore" revision="baf7d8068dd501cfa338d3a8b1b87216d6ce0571"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="50c4430e32849530ced32680fd6ee98963b3f7ac"/>
   <project name="platform/ndk" path="ndk" revision="e58ef003be4306bb53a8c11331146f39e4eab31f"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="0e7c060db684b409616fe67ea433ef19f5634c60"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="c792f0bd9fff7aea2887c60bbb3a9bbdb534ffa3"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="f7d9bf71cf6693474f3f2a81a4ba62c0fc5646aa"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="69d524e80cdf3981006627c65ac85f3a871238a3"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="8a05fd72770a3b1fc23f3216a45318ad393fc4ca"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="d8040bc7850e326b297045ccbd51bfd7bf566a53"/>
   <project name="platform/system/extras" path="system/extras" revision="576f57b6510de59c08568b53c0fb60588be8689e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="fe95bc6f83af5c18a73aa86c96e7fa7f79b91477"/>
   <project name="platform/system/netd" path="system/netd" revision="a6531f7befb49b1c81bc0de7e51c5482b308e1c5"/>
   <project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>
   <project name="platform/system/vold" path="system/vold" revision="42fa2a0f14f965970a4b629a176bbd2666edf017"/>
   <project name="platform/external/curl" path="external/curl" revision="e68addd988448959ea8157c5de637346b4180c33"/>
   <project name="platform/external/icu4c" path="external/icu4c" revision="d3ec7428eb276db43b7ed0544e09344a6014806c"/>
   <project name="platform/system/media" path="system/media" revision="c1332c21c608f4932a6d7e83450411cde53315ef"/>
@@ -128,16 +128,17 @@
   <project name="device/qcom/common" path="device/qcom/common" revision="54c32c2ddef066fbdf611d29e4b7c47e0363599e"/>
   <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="e7c90613521145db090dd24147afd5ceb5703190"/>
   <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="0865bc4134b67220df4058625fba29305d6b10c3"/>
   <project name="kernel_lk" path="bootable/bootloader/lk" remote="b2g" revision="fda40423ffa573dc6cafd3780515010cb2a086be"/>
   <project name="platform_bootable_recovery" path="bootable/recovery" remote="b2g" revision="26e78a979f3090dc196219e268467620b6c40ec5"/>
   <project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="30b96dfca99cb384bf520a16b81f3aba56f09907"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="5b71e40213f650459e95d35b6f14af7e88d8ab62"/>
   <project name="platform_external_libnfc-nci" path="external/libnfc-nci" remote="t2m" revision="4186bdecb4dae911b39a8202252cc2310d91b0be"/>
+  <project name="platform_external_libnfc-pn547" path="external/libnfc-pn547" remote="b2g" revision="5bb999b84b8adc14f6bea004d523ba258dea8188"/>
   <project name="platform/frameworks/av" path="frameworks/av" revision="65f5144987afff35a932262c0c5fad6ecce0c04a"/>
   <project name="platform/frameworks/base" path="frameworks/base" revision="da8e6bc53c8bc669da0bb627904d08aa293f2497"/>
   <project name="platform/frameworks/native" path="frameworks/native" revision="a46a9f1ac0ed5662d614c277cbb14eb3f332f365"/>
   <project name="platform/hardware/libhardware" path="hardware/libhardware" revision="7196881a0e9dd7bfbbcf0af64c8064e70f0fa094"/>
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="8d7676dfb68ee0cd069affedd5d1e97316a184ba"/>
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="2a1ded216a91bf62a72b1640cf01ab4998f37028"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="a74adcf8d88320d936daa8d20ce88ca0107fb916"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="9883ea57b0668d8f60dba025d4522dfa69a1fbfa"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="cba2f0bf49b882e0044c3cc583de8fcf83d2ffa4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
@@ -126,16 +126,17 @@
   <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="49417cfc622074daa3c76b345a199f6731375800"/>
   <project name="kernel_lk" path="bootable/bootloader/lk" remote="b2g" revision="6f00133ac0f47e90027bd7e263a16b405bfac503"/>
   <project name="platform_bootable_recovery" path="bootable/recovery" remote="b2g" revision="e81502511cda303c803e63f049574634bc96f9f2"/>
   <project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="81c4a859d75d413ad688067829d21b7ba9205f81"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="f0689ac1914cdbc59e53bdc9edd9013dc157c299"/>
   <project name="platform/external/bluetooth/glib" path="external/bluetooth/glib" revision="dd925f76e4f149c3d5571b80e12f7e24bbe89c59"/>
   <project name="platform/external/dbus" path="external/dbus" revision="ea87119c843116340f5df1d94eaf8275e1055ae8"/>
   <project name="platform_external_libnfc-nci" path="external/libnfc-nci" remote="t2m" revision="4186bdecb4dae911b39a8202252cc2310d91b0be"/>
+  <project name="platform_external_libnfc-pn547" path="external/libnfc-pn547" remote="b2g" revision="5bb999b84b8adc14f6bea004d523ba258dea8188"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="320b05a5761eb2a4816f7529c91ea49422979b55"/>
   <project name="platform/frameworks/av" path="frameworks/av" revision="0f7829661cd7125de9dc2c90eca2fa1dbc68dfbf"/>
   <project name="platform/frameworks/base" path="frameworks/base" revision="f9309b4463abd80e0876cd113c892e31d62113b1"/>
   <project name="platform/frameworks/native" path="frameworks/native" revision="268d569074237b53617db8211400d4e3c947ae73"/>
   <project name="platform/hardware/libhardware" path="hardware/libhardware" revision="8b39ee0db3203247e983db773799f7f4ff2f69ce"/>
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="de4ade568b273781416638fbbce13ff31b636ada"/>
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="5e110615212302c5d798a3c223dcee458817651c"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="fa9ffd47948eb24466de227e48fe9c4a7c5e7711"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "e45c5dbdcfc2d598c889dfbea72fa11157422afe", 
+        "git_revision": "cba2f0bf49b882e0044c3cc583de8fcf83d2ffa4", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "ecc956a2747963c2db6edf513cd3a8a75ca8884a", 
+    "revision": "23474274d441d400d43cdec6eaef41ff23443d80", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cba2f0bf49b882e0044c3cc583de8fcf83d2ffa4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cba2f0bf49b882e0044c3cc583de8fcf83d2ffa4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="cba2f0bf49b882e0044c3cc583de8fcf83d2ffa4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
@@ -113,17 +113,17 @@
   <project name="platform/libnativehelper" path="libnativehelper" revision="4792069e90385889b0638e97ae62c67cdf274e22"/>
   <project name="platform/ndk" path="ndk" revision="7666b97bbaf1d645cdd6b4430a367b7a2bb53369"/>
   <project name="platform/prebuilts/misc" path="prebuilts/misc" revision="f6ab40b3257abc07741188fd173ac392575cc8d2"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="e52099755d0bd3a579130eefe8e58066cc6c0cb6"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="02c32feb2fe97037be0ac4dace3a6a5025ac895d"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="8a05fd72770a3b1fc23f3216a45318ad393fc4ca"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="d8040bc7850e326b297045ccbd51bfd7bf566a53"/>
   <project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
   <project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="fe95bc6f83af5c18a73aa86c96e7fa7f79b91477"/>
   <project name="platform/system/media" path="system/media" revision="d90b836f66bf1d9627886c96f3a2d9c3007fbb80"/>
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="cba2f0bf49b882e0044c3cc583de8fcf83d2ffa4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -241,17 +241,16 @@ pref("lightweightThemes.update.enabled",
 pref("lightweightThemes.getMoreURL", "https://addons.mozilla.org/%LOCALE%/firefox/themes");
 pref("lightweightThemes.recommendedThemes", "[{\"id\":\"recommended-1\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/a-web-browser-renaissance/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.header.jpg\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.footer.jpg\",\"textcolor\":\"#000000\",\"accentcolor\":\"#f2d9b1\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.preview.jpg\",\"author\":\"Sean.Martell\",\"version\":\"0\"},{\"id\":\"recommended-2\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/space-fantasy/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.header.jpg\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.footer.jpg\",\"textcolor\":\"#ffffff\",\"accentcolor\":\"#d9d9d9\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.preview.jpg\",\"author\":\"fx5800p\",\"version\":\"1.0\"},{\"id\":\"recommended-3\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/linen-light/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.header.png\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.footer.png\",\"textcolor\":\"#None\",\"accentcolor\":\"#ada8a8\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.icon.png\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.preview.png\",\"author\":\"DVemer\",\"version\":\"1.0\"},{\"id\":\"recommended-4\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/pastel-gradient/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.header.png\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.footer.png\",\"textcolor\":\"#000000\",\"accentcolor\":\"#000000\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.icon.png\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.preview.png\",\"author\":\"darrinhenein\",\"version\":\"1.0\"},{\"id\":\"recommended-5\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/carbon-light/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.header.png\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.footer.png\",\"textcolor\":\"#3b3b3b\",\"accentcolor\":\"#2e2e2e\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.preview.jpg\",\"author\":\"Jaxivo\",\"version\":\"1.0\"}]");
 
 // 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.pinnedTabUrl", "https://support.mozilla.org/%LOCALE%/kb/pinned-tabs-keep-favorite-websites-open");
 pref("browser.uitour.url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/tour/");
 
 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);
 
@@ -1492,16 +1491,17 @@ pref("devtools.gcli.eagerHelper", 2);
 pref("devtools.gcli.jquerySrc", "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js");
 pref("devtools.gcli.lodashSrc", "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js");
 pref("devtools.gcli.underscoreSrc", "https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js");
 
 // Remember the Web Console filters
 pref("devtools.webconsole.filter.network", true);
 pref("devtools.webconsole.filter.networkinfo", false);
 pref("devtools.webconsole.filter.netwarn", true);
+pref("devtools.webconsole.filter.netxhr", false);
 pref("devtools.webconsole.filter.csserror", true);
 pref("devtools.webconsole.filter.cssparser", false);
 pref("devtools.webconsole.filter.csslog", false);
 pref("devtools.webconsole.filter.exception", true);
 pref("devtools.webconsole.filter.jswarn", true);
 pref("devtools.webconsole.filter.jslog", false);
 pref("devtools.webconsole.filter.error", true);
 pref("devtools.webconsole.filter.warn", true);
@@ -1509,16 +1509,17 @@ pref("devtools.webconsole.filter.info", 
 pref("devtools.webconsole.filter.log", true);
 pref("devtools.webconsole.filter.secerror", true);
 pref("devtools.webconsole.filter.secwarn", true);
 
 // Remember the Browser Console filters
 pref("devtools.browserconsole.filter.network", true);
 pref("devtools.browserconsole.filter.networkinfo", false);
 pref("devtools.browserconsole.filter.netwarn", true);
+pref("devtools.browserconsole.filter.netxhr", false);
 pref("devtools.browserconsole.filter.csserror", true);
 pref("devtools.browserconsole.filter.cssparser", false);
 pref("devtools.browserconsole.filter.csslog", false);
 pref("devtools.browserconsole.filter.exception", true);
 pref("devtools.browserconsole.filter.jswarn", true);
 pref("devtools.browserconsole.filter.jslog", true);
 pref("devtools.browserconsole.filter.error", true);
 pref("devtools.browserconsole.filter.warn", true);
@@ -1697,17 +1698,17 @@ pref("security.cert_pinning.enforcement_
 // Override the Gecko-default value of false for Firefox.
 pref("plain_text.wrap_long_lines", true);
 
 // If this turns true, Moz*Gesture events are not called stopPropagation()
 // before content.
 pref("dom.debug.propagate_gesture_events_through_content", false);
 
 // The request URL of the GeoLocation backend.
-pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%GOOGLE_API_KEY%");
+pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
 
 // Necko IPC security checks only needed for app isolation for cookies/cache/etc:
 // currently irrelevant for desktop e10s
 pref("network.disable.ipc.security", true);
 
 // CustomizableUI debug logging.
 pref("browser.uiCustomization.debug", false);
 
--- a/browser/base/content/abouthome/aboutHome.js
+++ b/browser/base/content/abouthome/aboutHome.js
@@ -141,17 +141,17 @@ 0P/y6/7299z+H4QrdGsoib8JAAAAAElFTkSuQmCC
 //   * add a <span/> for it in aboutHome.xhtml
 //   * add an entry here in the proper ordering (based on spans)
 // The <a/> part of the snippet will be linked to the corresponding url.
 const DEFAULT_SNIPPETS_URLS = [
   "https://www.mozilla.org/firefox/features/?utm_source=snippet&utm_medium=snippet&utm_campaign=default+feature+snippet"
 , "https://addons.mozilla.org/firefox/?utm_source=snippet&utm_medium=snippet&utm_campaign=addons"
 ];
 
-const SNIPPETS_UPDATE_INTERVAL_MS = 86400000; // 1 Day.
+const SNIPPETS_UPDATE_INTERVAL_MS = 14400000; // 4 hours.
 
 // IndexedDB storage constants.
 const DATABASE_NAME = "abouthome";
 const DATABASE_VERSION = 1;
 const DATABASE_STORAGE = "persistent";
 const SNIPPETS_OBJECTSTORE_NAME = "snippets";
 
 // This global tracks if the page has been set up before, to prevent double inits
--- a/browser/base/content/browser-ctrlTab.js
+++ b/browser/base/content/browser-ctrlTab.js
@@ -44,41 +44,35 @@ var tabPreviews = {
     }
 
     return this.capture(aTab, !aTab.hasAttribute("busy"));
   },
 
   capture: function tabPreviews_capture(aTab, aShouldCache) {
     let browser = aTab.linkedBrowser;
     let uri = browser.currentURI.spec;
-
-    // FIXME: The gBrowserThumbnails._shouldCapture determines whether
-    //        thumbnails should be written to disk. This should somehow be part
-    //        of the PageThumbs API. (bug 1062414)
-    if (aShouldCache &&
-        gBrowserThumbnails._shouldCapture(browser)) {
-      let img = new Image;
-
-      PageThumbs.captureAndStore(browser, function () {
-        img.src = PageThumbs.getThumbnailURL(uri);
-      });
-
-      aTab.__thumbnail = img;
-      aTab.__thumbnail_lastURI = uri;
-      return img;
-    }
-
     let canvas = PageThumbs.createCanvas(window);
-
-    if (aShouldCache) {
-      aTab.__thumbnail = canvas;
-      aTab.__thumbnail_lastURI = uri;
-    }
-
-    PageThumbs.captureToCanvas(browser, canvas);
+    PageThumbs.shouldStoreThumbnail(browser, (aDoStore) => {
+      if (aDoStore && aShouldCache) {
+        PageThumbs.captureAndStore(browser, function () {
+          let img = new Image;
+          img.src = PageThumbs.getThumbnailURL(uri);
+          aTab.__thumbnail = img;
+          aTab.__thumbnail_lastURI = uri;
+          canvas.getContext("2d").drawImage(img, 0, 0);
+        });
+      } else {
+        PageThumbs.captureToCanvas(browser, canvas, () => {
+          if (aShouldCache) {
+            aTab.__thumbnail = canvas;
+            aTab.__thumbnail_lastURI = uri;
+          }
+        });
+      }
+    });
     return canvas;
   },
 
   handleEvent: function tabPreviews_handleEvent(event) {
     switch (event.type) {
       case "TabSelect":
         if (this._selectedTab &&
             this._selectedTab.parentNode &&
--- a/browser/base/content/browser-fxaccounts.js
+++ b/browser/base/content/browser-fxaccounts.js
@@ -343,18 +343,18 @@ let gFxAccounts = {
   openPreferences: function () {
     openPreferences("paneSync");
   },
 
   openAccountsPage: function (action, urlParams={}) {
     // An entryPoint param is used for server-side metrics.  If the current tab
     // is UITour, assume that it initiated the call to this method and override
     // the entryPoint accordingly.
-    if (UITour.originTabs.get(window) &&
-        UITour.originTabs.get(window).has(gBrowser.selectedTab)) {
+    if (UITour.tourBrowsersByWindow.get(window) &&
+        UITour.tourBrowsersByWindow.get(window).has(gBrowser.selectedBrowser)) {
       urlParams.entryPoint = "uitour";
     }
     let params = new URLSearchParams();
     if (action) {
       params.set("action", action);
     }
     for (let name in urlParams) {
       if (urlParams[name] !== undefined) {
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -300,17 +300,18 @@ let gSyncUI = {
                                 .getService(Components.interfaces.nsISupports)
                                 .wrappedJSObject;
     if (xps.fxAccountsEnabled) {
       fxAccounts.getSignedInUser().then(userData => {
         if (userData) {
           this.openPrefs();
         } else {
           // If the user is also in an uitour, set the entrypoint to `uitour`
-          if (UITour.originTabs.get(window) && UITour.originTabs.get(window).has(gBrowser.selectedTab)) {
+          if (UITour.tourBrowsersByWindow.get(window) &&
+              UITour.tourBrowsersByWindow.get(window).has(gBrowser.selectedBrowser)) {
             entryPoint = "uitour";
           }
           switchToTabHavingURI("about:accounts?entrypoint=" + entryPoint, true, {
             replaceQueryString: true
           });
         }
       });
     } else {
--- a/browser/base/content/browser-thumbnails.js
+++ b/browser/base/content/browser-thumbnails.js
@@ -91,102 +91,46 @@ let gBrowserThumbnails = {
                                                    aRequest, aStateFlags, aStatus) {
     if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
         aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK)
       this._delayedCapture(aBrowser);
   },
 
   _capture: function Thumbnails_capture(aBrowser) {
     // Only capture about:newtab top sites.
-    if (this._topSiteURLs.indexOf(aBrowser.currentURI.spec) >= 0 &&
-        this._shouldCapture(aBrowser))
-      PageThumbs.captureAndStoreIfStale(aBrowser);
+    if (this._topSiteURLs.indexOf(aBrowser.currentURI.spec) == -1)
+      return;
+    this._shouldCapture(aBrowser, function (aResult) {
+      if (aResult) {
+        PageThumbs.captureAndStoreIfStale(aBrowser);
+      }
+    });
   },
 
   _delayedCapture: function Thumbnails_delayedCapture(aBrowser) {
     if (this._timeouts.has(aBrowser))
       clearTimeout(this._timeouts.get(aBrowser));
     else
       aBrowser.addEventListener("scroll", this, true);
 
     let timeout = setTimeout(function () {
       this._clearTimeout(aBrowser);
       this._capture(aBrowser);
     }.bind(this), this._captureDelayMS);
 
     this._timeouts.set(aBrowser, timeout);
   },
 
-  // FIXME: This should be part of the PageThumbs API. (bug 1062414)
-  _shouldCapture: function Thumbnails_shouldCapture(aBrowser) {
+  _shouldCapture: function Thumbnails_shouldCapture(aBrowser, aCallback) {
     // Capture only if it's the currently selected tab.
-    if (aBrowser != gBrowser.selectedBrowser)
-      return false;
-
-    // Don't capture in per-window private browsing mode.
-    if (PrivateBrowsingUtils.isWindowPrivate(window))
-      return false;
-
-    let doc = aBrowser.contentDocument;
-
-    // FIXME Bug 720575 - Don't capture thumbnails for SVG or XML documents as
-    //       that currently regresses Talos SVG tests.
-    if (doc instanceof SVGDocument || doc instanceof XMLDocument)
-      return false;
-
-    // Don't take screenshots of about: pages.
-    if (aBrowser.currentURI.schemeIs("about"))
-      return false;
-
-    // FIXME e10s work around, we need channel information. bug 1073957
-    if (!aBrowser.docShell)
-      return true;
-
-    // There's no point in taking screenshot of loading pages.
-    if (aBrowser.docShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE)
-      return false;
-
-    let channel = aBrowser.docShell.currentDocumentChannel;
-
-    // No valid document channel. We shouldn't take a screenshot.
-    if (!channel)
-      return false;
-
-    // Don't take screenshots of internally redirecting about: pages.
-    // This includes error pages.
-    let uri = channel.originalURI;
-    if (uri.schemeIs("about"))
-      return false;
-
-    let httpChannel;
-    try {
-      httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
-    } catch (e) { /* Not an HTTP channel. */ }
-
-    if (httpChannel) {
-      // Continue only if we have a 2xx status code.
-      try {
-        if (Math.floor(httpChannel.responseStatus / 100) != 2)
-          return false;
-      } catch (e) {
-        // Can't get response information from the httpChannel
-        // because mResponseHead is not available.
-        return false;
-      }
-
-      // Cache-Control: no-store.
-      if (httpChannel.isNoStoreResponse())
-        return false;
-
-      // Don't capture HTTPS pages unless the user explicitly enabled it.
-      if (uri.schemeIs("https") && !this._sslDiskCacheEnabled)
-        return false;
+    if (aBrowser != gBrowser.selectedBrowser) {
+      aCallback(false);
+      return;
     }
-
-    return true;
+    PageThumbs.shouldStoreThumbnail(aBrowser, aCallback);
   },
 
   get _topSiteURLs() {
     return NewTabUtils.links.getLinks().reduce((urls, link) => {
       if (link)
         urls.push(link.url);
       return urls;
     }, []);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -6289,41 +6289,31 @@ var OfflineApps = {
     }
   }
 };
 
 var IndexedDBPromptHelper = {
   _permissionsPrompt: "indexedDB-permissions-prompt",
   _permissionsResponse: "indexedDB-permissions-response",
 
-  _quotaPrompt: "indexedDB-quota-prompt",
-  _quotaResponse: "indexedDB-quota-response",
-  _quotaCancel: "indexedDB-quota-cancel",
-
   _notificationIcon: "indexedDB-notification-icon",
 
   init:
   function IndexedDBPromptHelper_init() {
     Services.obs.addObserver(this, this._permissionsPrompt, false);
-    Services.obs.addObserver(this, this._quotaPrompt, false);
-    Services.obs.addObserver(this, this._quotaCancel, false);
   },
 
   uninit:
   function IndexedDBPromptHelper_uninit() {
     Services.obs.removeObserver(this, this._permissionsPrompt);
-    Services.obs.removeObserver(this, this._quotaPrompt);
-    Services.obs.removeObserver(this, this._quotaCancel);
   },
 
   observe:
   function IndexedDBPromptHelper_observe(subject, topic, data) {
-    if (topic != this._permissionsPrompt &&
-        topic != this._quotaPrompt &&
-        topic != this._quotaCancel) {
+    if (topic != this._permissionsPrompt) {
       throw new Error("Unexpected topic!");
     }
 
     var requestor = subject.QueryInterface(Ci.nsIInterfaceRequestor);
 
     var contentWindow = requestor.getInterface(Ci.nsIDOMWindow);
     var contentDocument = contentWindow.document;
     var browserWindow =
@@ -6341,24 +6331,16 @@ var IndexedDBPromptHelper = {
 
     var message;
     var responseTopic;
     if (topic == this._permissionsPrompt) {
       message = gNavigatorBundle.getFormattedString("offlineApps.available",
                                                     [ host ]);
       responseTopic = this._permissionsResponse;
     }
-    else if (topic == this._quotaPrompt) {
-      message = gNavigatorBundle.getFormattedString("indexedDB.usage",
-                                                    [ host, data ]);
-      responseTopic = this._quotaResponse;
-    }
-    else if (topic == this._quotaCancel) {
-      responseTopic = this._quotaResponse;
-    }
 
     const hiddenTimeoutDuration = 30000; // 30 seconds
     const firstTimeoutDuration = 300000; // 5 minutes
 
     var timeoutId;
 
     var observer = requestor.getInterface(Ci.nsIObserver);
 
@@ -6379,19 +6361,17 @@ var IndexedDBPromptHelper = {
         callback: function() {
           clearTimeout(timeoutId);
           observer.observe(null, responseTopic,
                            Ci.nsIPermissionManager.DENY_ACTION);
         }
       }
     ];
 
-    // This will be set to the result of PopupNotifications.show() below, or to
-    // the result of PopupNotifications.getNotification() if this is a
-    // quotaCancel notification.
+    // This will be set to the result of PopupNotifications.show().
     var notification;
 
     function timeoutNotification() {
       // Remove the notification.
       if (notification) {
         notification.remove();
       }
 
@@ -6421,23 +6401,16 @@ var IndexedDBPromptHelper = {
         // If the popup is being re-shown then clear the timeout allowing
         // unlimited waiting.
         if (state == "shown") {
           clearTimeout(timeoutId);
         }
       }
     };
 
-    if (topic == this._quotaCancel) {
-      notification = PopupNotifications.getNotification(this._quotaPrompt,
-                                                        browser);
-      timeoutNotification();
-      return;
-    }
-
     notification = PopupNotifications.show(browser, topic, message,
                                            this._notificationIcon, mainAction,
                                            secondaryActions, options);
 
     // Set the timeoutId after the popup has been created, and use the long
     // timeout value. If the user doesn't notice the popup after this amount of
     // time then it is most likely not visible and we want to alert the page.
     timeoutId = setTimeout(timeoutNotification, firstTimeoutDuration);
--- a/browser/base/content/pageinfo/permissions.js
+++ b/browser/base/content/pageinfo/permissions.js
@@ -147,19 +147,16 @@ function createRow(aPartId) {
 }
 
 function onCheckboxClick(aPartId)
 {
   var command  = document.getElementById("cmd_" + aPartId + "Toggle");
   var checkbox = document.getElementById(aPartId + "Def");
   if (checkbox.checked) {
     SitePermissions.remove(gPermURI, aPartId);
-    if (aPartId == "indexedDB") {
-      SitePermissions.remove(gPermURI, "indexedDB-unlimited");
-    }
     command.setAttribute("disabled", "true");
     var perm = SitePermissions.getDefault(aPartId);
     setRadioState(aPartId, perm);
   }
   else {
     onRadioClick(aPartId);
     command.removeAttribute("disabled");
   }
@@ -205,17 +202,16 @@ function initIndexedDBRow()
 
 function onIndexedDBClear()
 {
   Components.classes["@mozilla.org/dom/quota/manager;1"]
             .getService(nsIQuotaManager)
             .clearStoragesForURI(gPermURI);
 
   SitePermissions.remove(gPermURI, "indexedDB");
-  SitePermissions.remove(gPermURI, "indexedDB-unlimited");
   initIndexedDBRow();
 }
 
 function onIndexedDBUsageCallback(uri, usage, fileUsage)
 {
   if (!uri.equals(gPermURI)) {
     throw new Error("Callback received for bad URI: " + uri);
   }
--- a/browser/base/content/searchSuggestionUI.js
+++ b/browser/base/content/searchSuggestionUI.js
@@ -235,26 +235,21 @@ SearchSuggestionUIController.prototype =
 
   _onMousedown: function (event) {
     let idx = this._indexOfTableRowOrDescendent(event.target);
     let suggestion = this.suggestionAtIndex(idx);
     this._stickyInputValue = suggestion;
 
     // Commit composition string forcibly, because setting input value does not
     // work if input has composition string (see bug 1115616 and bug 632744).
-    try {
-      let imeEditor = this.input.editor.QueryInterface(Components.interfaces.nsIEditorIMESupport);
-      if (imeEditor.composing) {
-        // Ignore input event for compisition end to avoid getting suggestion
-        // again.
-        this._ignoreInputEvent = true;
-        imeEditor.forceCompositionEnd();
-        this._ignoreInputEvent = false;
-      }
-    } catch(e) { }
+    // Ignore input event for composition end to avoid getting suggestion again.
+    this._ignoreInputEvent = true;
+    this.input.blur();
+    this.input.focus();
+    this._ignoreInputEvent = false;
 
     this.input.value = suggestion;
     this.input.setAttribute("selection-index", idx);
     this.input.setAttribute("selection-kind", "mouse");
     this._hideSuggestions();
     if (this.onClick) {
       this.onClick.call(null);
     }
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -2651,25 +2651,16 @@
       <method name="replaceTabWithWindow">
         <parameter name="aTab"/>
         <parameter name="aOptions"/>
         <body>
           <![CDATA[
             if (this.tabs.length == 1)
               return null;
 
-            let event = new CustomEvent("TabBecomingWindow", {
-              bubbles: true,
-              cancelable: true
-            });
-            aTab.dispatchEvent(event);
-            if (event.defaultPrevented) {
-              return null;
-            }
-
             var options = "chrome,dialog=no,all";
             for (var name in aOptions)
               options += "," + name + "=" + aOptions[name];
 
             // tell a new window to take the "dropped" tab
             return window.openDialog(getBrowserURL(), "_blank", options, aTab);
           ]]>
         </body>
--- a/browser/base/content/test/general/browser_aboutHome.js
+++ b/browser/base/content/test/general/browser_aboutHome.js
@@ -376,16 +376,66 @@ let gTests = [
       // Empty the search input, causing the suggestions to be hidden.
       EventUtils.synthesizeKey("a", { accelKey: true });
       EventUtils.synthesizeKey("VK_DELETE", {});
       ok(table.hidden, "Search suggestion table hidden");
     });
   }
 },
 {
+  desc: "Clicking suggestion list while composing",
+  setup: function() {},
+  run: function()
+  {
+    return Task.spawn(function* () {
+      // Start composition and type "x"
+      let input = gBrowser.contentDocument.getElementById("searchText");
+      input.focus();
+      EventUtils.synthesizeComposition({ type: "compositionstart", data: "" });
+      EventUtils.synthesizeComposition({ type: "compositionupdate", data: "x" });
+      EventUtils.synthesizeCompositionChange({
+        composition: {
+          string: "x",
+          clauses: [
+            { length: 1, attr: EventUtils.COMPOSITION_ATTR_RAWINPUT }
+          ]
+        },
+        caret: { start: 1, length: 0 }
+      });
+
+      // Wait for the search suggestions to become visible.
+      let table =
+        gBrowser.contentDocument.getElementById("searchSuggestionTable");
+      let deferred = Promise.defer();
+      let observer = new MutationObserver(() => {
+        if (input.getAttribute("aria-expanded") == "true") {
+          observer.disconnect();
+          ok(!table.hidden, "Search suggestion table unhidden");
+          deferred.resolve();
+        }
+      });
+      observer.observe(input, {
+        attributes: true,
+        attributeFilter: ["aria-expanded"],
+      });
+      yield deferred.promise;
+
+      // Click the second suggestion.
+      let expectedURL = Services.search.currentEngine.
+                        getSubmission("xbar", null, "homepage").
+                        uri.spec;
+      let loadPromise = waitForDocLoadAndStopIt(expectedURL);
+      let row = table.children[1];
+      EventUtils.sendMouseEvent({ type: "mousedown" }, row, gBrowser.contentWindow);
+      yield loadPromise;
+      ok(input.value == "xbar", "Suggestion is selected");
+    });
+  }
+},
+{
   desc: "Cmd+k should focus the search box in the page when the search box in the toolbar is absent",
   setup: function () {
     // Remove the search bar from toolbar
     CustomizableUI.removeWidgetFromArea("search-container");
   },
   run: Task.async(function* () {
     let doc = gBrowser.selectedBrowser.contentDocument;
     let logo = doc.getElementById("brandLogo");
--- a/browser/base/content/test/general/browser_action_searchengine.js
+++ b/browser/base/content/test/general/browser_action_searchengine.js
@@ -21,17 +21,17 @@ add_task(function* () {
     Services.search.currentEngine = originalEngine;
     let engine = Services.search.getEngineByName("MozSearch");
     Services.search.removeEngine(engine);
 
     try {
       gBrowser.removeTab(tab);
     } catch(ex) { /* tab may have already been closed in case of failure */ }
 
-    return promiseClearHistory();
+    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"}`,
--- a/browser/base/content/test/general/browser_action_searchengine_alias.js
+++ b/browser/base/content/test/general/browser_action_searchengine_alias.js
@@ -21,17 +21,17 @@ add_task(function* () {
     let engine = Services.search.getEngineByName("MozSearch");
     Services.search.removeEngine(engine);
     Services.prefs.clearUserPref("browser.urlbar.unifiedcomplete");
 
     try {
       gBrowser.removeTab(tab);
     } catch(ex) { /* tab may have already been closed in case of failure */ }
 
-    return promiseClearHistory();
+    return PlacesTestUtils.clearHistory();
   });
 
   yield promiseAutocompleteResultPopup("moz open a search");
 
   let result = gURLBar.popup.richlistbox.children[0];
   ok(result.hasAttribute("image"), "Result should have an image attribute");
   // Image attribute gets a suffix (-moz-resolution) added in the value.
   ok(result.getAttribute("image").startsWith(engine.iconURI.spec),
--- a/browser/base/content/test/general/browser_autocomplete_autoselect.js
+++ b/browser/base/content/test/general/browser_autocomplete_autoselect.js
@@ -10,17 +10,17 @@ function is_selected(index) {
 
 add_task(function*() {
   // This test is only relevant if UnifiedComplete is enabled.
   if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
     todo(false, "Stop supporting old autocomplete components.");
     return;
   }
 
-  registerCleanupFunction(promiseClearHistory);
+  registerCleanupFunction(() => PlacesTestUtils.clearHistory());
 
   let visits = [];
   repeat(10, i => {
     visits.push({
       uri: makeURI("http://example.com/autocomplete/?" + i),
     });
   });
   yield PlacesTestUtils.addVisits(visits);
--- a/browser/base/content/test/general/browser_autocomplete_oldschool_wrap.js
+++ b/browser/base/content/test/general/browser_autocomplete_oldschool_wrap.js
@@ -10,17 +10,17 @@ function is_selected(index) {
 
 add_task(function*() {
   // This test is only relevant if UnifiedComplete is *disabled*.
   if (Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
     ok(true, "Don't run this test with UnifiedComplete enabled.")
     return;
   }
 
-  registerCleanupFunction(promiseClearHistory);
+  registerCleanupFunction(() => PlacesTestUtils.clearHistory());
 
   let visits = [];
   repeat(10, i => {
     visits.push({
       uri: makeURI("http://example.com/autocomplete/?" + i),
     });
   });
   yield PlacesTestUtils.addVisits(visits);
--- a/browser/base/content/test/general/browser_bug1003461-switchtab-override.js
+++ b/browser/base/content/test/general/browser_bug1003461-switchtab-override.js
@@ -61,10 +61,10 @@ add_task(function* test_switchtab_overri
   whenTabLoaded(secondTab, deferred.resolve);
 
   EventUtils.synthesizeKey("VK_SHIFT" , { type: "keydown" });
   EventUtils.synthesizeKey("VK_RETURN" , { });
   info(`gURLBar.value = ${gURLBar.value}`);
   EventUtils.synthesizeKey("VK_SHIFT" , { type: "keyup" });
   yield deferred.promise;
 
-  yield promiseClearHistory();
+  yield PlacesTestUtils.clearHistory();
 });
--- a/browser/base/content/test/general/browser_bug1024133-switchtab-override-keynav.js
+++ b/browser/base/content/test/general/browser_bug1024133-switchtab-override-keynav.js
@@ -13,17 +13,17 @@ add_task(function* test_switchtab_overri
 
   info("Opening and selecting second tab");
   let secondTab = gBrowser.selectedTab = gBrowser.addTab();
   registerCleanupFunction(() => {
     try {
       gBrowser.removeTab(tab);
       gBrowser.removeTab(secondTab);
     } catch(ex) { /* tabs may have already been closed in case of failure */ }
-    return promiseClearHistory();
+    return PlacesTestUtils.clearHistory();
   });
 
   gURLBar.focus();
   gURLBar.value = "dummy_pag";
   EventUtils.synthesizeKey("e" , {});
   yield promiseSearchComplete();
 
   info("Select second autocomplete popup entry");
--- a/browser/base/content/test/general/browser_bug581253.js
+++ b/browser/base/content/test/general/browser_bug581253.js
@@ -65,38 +65,22 @@ function onPanelShown(aEvent) {
     tagsField.focus();
 
     StarUI.panel.addEventListener("popuphidden", onPanelHidden, false);
     let removeButton = document.getElementById("editBookmarkPanelRemoveButton");
     removeButton.click();
   }
 }
 
-/**
- * Clears history invoking callback when done.
- */
-function waitForClearHistory(aCallback)
-{
-  let observer = {
-    observe: function(aSubject, aTopic, aData)
-    {
-      Services.obs.removeObserver(this, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
-      aCallback(aSubject, aTopic, aData);
-    }
-  };
-  Services.obs.addObserver(observer, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
-  PlacesUtils.bhistory.removeAllPages();
-}
-
 function onPanelHidden(aEvent) {
   if (aEvent.target == StarUI.panel) {
     StarUI.panel.removeEventListener("popuphidden", arguments.callee, false);
 
     executeSoon(function() {
       ok(!PlacesUtils.bookmarks.isBookmarked(makeURI(testURL)),
          "the bookmark for the test url has been removed");
       is(BookmarkingUI.status, BookmarkingUI.STATUS_UNSTARRED,
          "star button indicates that the bookmark has been removed");
       gBrowser.removeCurrentTab();
-      waitForClearHistory(finish);
+      PlacesTestUtils.clearHistory().then(finish);
     });
   }
 }
--- a/browser/base/content/test/general/browser_sanitizeDialog.js
+++ b/browser/base/content/test/general/browser_sanitizeDialog.js
@@ -971,50 +971,42 @@ function formNameExists(name)
 
   return deferred.promise;
 }
 
 /**
  * Removes all history visits, downloads, and form entries.
  */
 function blankSlate() {
-  PlacesUtils.bhistory.removeAllPages();
-
-  // The promise is resolved only when removing both downloads and form history are done.
-  let deferred = Promise.defer();
-  let formHistoryDone = false, downloadsDone = false;
-
-  Task.spawn(function deleteAllDownloads() {
+  let deleteDownloads = Task.spawn(function* deleteAllDownloads() {
     let publicList = yield Downloads.getList(Downloads.PUBLIC);
     let downloads = yield publicList.getAll();
     for (let download of downloads) {
       yield publicList.remove(download);
       yield download.finalize(true);
     }
-    downloadsDone = true;
-    if (formHistoryDone) {
-      deferred.resolve();
-    }
   }).then(null, Components.utils.reportError);
 
-  FormHistory.update({ op: "remove" },
-                     { handleError: function (error) {
-                         do_throw("Error occurred updating form history: " + error);
-                         deferred.reject(error);
-                       },
-                       handleCompletion: function (reason) {
-                         if (!reason) {
-                           formHistoryDone = true;
-                           if (downloadsDone) {
-                             deferred.resolve();
-                           }
-                         }
-                       }
-                     });
-  return deferred.promise;
+  let updateFormHistory = new Promise((resolve, reject) => {
+    FormHistory.update({op: "remove"}, {
+      handleCompletion(reason) {
+        if (!reason) {
+          resolve();
+        }
+      },
+
+      handleError(error) {
+        do_throw("Error occurred updating form history: " + error);
+        reject(error);
+      }
+    });
+  });
+
+  return Promise.all([
+    PlacesTestUtils.clearHistory(), deleteDownloads, updateFormHistory]);
 }
 
 /**
  * Ensures that the given pref is the expected value.
  *
  * @param aPrefName
  *        The pref's sub-branch under the privacy branch
  * @param aExpectedVal
--- a/browser/base/content/test/general/browser_search_favicon.js
+++ b/browser/base/content/test/general/browser_search_favicon.js
@@ -67,17 +67,17 @@ function promiseAddVisits(aPlaceInfo) {
   });
 }
 
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref(gUnifiedCompletePref);
   Services.prefs.clearUserPref(gRestyleSearchesPref);
   Services.search.currentEngine = gOriginalEngine;
   Services.search.removeEngine(gEngine);
-  return promiseClearHistory();
+  return PlacesTestUtils.clearHistory();
 });
 
 add_task(function*() {
   Services.prefs.setBoolPref(gUnifiedCompletePref, true);
   Services.prefs.setBoolPref(gRestyleSearchesPref, true);
 });
 
 add_task(function*() {
--- a/browser/base/content/test/general/browser_tabMatchesInAwesomebar.js
+++ b/browser/base/content/test/general/browser_tabMatchesInAwesomebar.js
@@ -145,18 +145,17 @@ function waitForRestoredTab(tab) {
 
 function nextStep() {
   if (gTestSteps.length == 0) {
     while (gBrowser.tabs.length > 1) {
       gBrowser.selectTabAtIndex(1);
       gBrowser.removeCurrentTab();
     }
 
-    waitForClearHistory(finish);
-
+    PlacesTestUtils.clearHistory().then(finish);
     return;
   }
 
   var stepFunc = gTestSteps.shift();
   stepFunc();
 }
 
 function ensure_opentabs_match_db(aCallback) {
@@ -179,32 +178,16 @@ function ensure_opentabs_match_db(aCallb
       else
         tabs[url]++;
     }
   }
 
   checkAutocompleteResults(tabs, aCallback);
 }
 
-/**
- * Clears history invoking callback when done.
- */
-function waitForClearHistory(aCallback) {
-  const TOPIC_EXPIRATION_FINISHED = "places-expiration-finished";
-  let observer = {
-    observe: function(aSubject, aTopic, aData) {
-      Services.obs.removeObserver(this, TOPIC_EXPIRATION_FINISHED);
-      aCallback();
-    }
-  };
-  Services.obs.addObserver(observer, TOPIC_EXPIRATION_FINISHED, false);
-
-  PlacesUtils.bhistory.removeAllPages();
-}
-
 function checkAutocompleteResults(aExpected, aCallback)
 {
   gController.input = {
     timeout: 10,
     textValue: "",
     searches: ["history"],
     searchParam: "enable-actions",
     popupOpen: false,
--- a/browser/base/content/test/general/browser_urlbarAutoFillTrimURLs.js
+++ b/browser/base/content/test/general/browser_urlbarAutoFillTrimURLs.js
@@ -56,30 +56,22 @@ function continue_test() {
         // Now ensure selecting from the popup correctly trims.
         if (Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
           is(gURLBar.controller.matchCount, 2, "Found the expected number of matches");
         else
           is(gURLBar.controller.matchCount, 1, "Found the expected number of matches");
         EventUtils.synthesizeKey("VK_DOWN", {});
         is(gURLBar.textValue, "www.autofilltrimurl.com/whatever", "trim was applied correctly");
         gURLBar.closePopup();
-        waitForClearHistory(finish);
+        PlacesTestUtils.clearHistory().then(finish);
       });
     });
   });
 }
 
-function waitForClearHistory(aCallback) {
-  Services.obs.addObserver(function observeCH(aSubject, aTopic, aData) {
-    Services.obs.removeObserver(observeCH, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
-    aCallback();
-  }, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
-  PlacesUtils.bhistory.removeAllPages();
-}
-
 let gOnSearchComplete = null;
 function waitForSearchComplete(aCallback) {
   info("Waiting for onSearchComplete");
   if (!gOnSearchComplete) {
     gOnSearchComplete = gURLBar.onSearchComplete;
     registerCleanupFunction(() => {
       gURLBar.onSearchComplete = gOnSearchComplete;
     });
--- a/browser/base/content/test/general/browser_urlbarEnterAfterMouseOver.js
+++ b/browser/base/content/test/general/browser_urlbarEnterAfterMouseOver.js
@@ -11,19 +11,19 @@ function* promiseAutoComplete(inputText)
   yield promiseSearchComplete();
 }
 
 function is_selected(index) {
   is(gURLBar.popup.richlistbox.selectedIndex, index, `Item ${index + 1} should be selected`);
 }
 
 add_task(function*() {
-  registerCleanupFunction(promiseClearHistory);
+  registerCleanupFunction(() => PlacesTestUtils.clearHistory());
 
-  yield promiseClearHistory();
+  yield PlacesTestUtils.clearHistory();
   let tabCount = gBrowser.tabs.length;
 
   let visits = [];
   repeat(10, i => {
     visits.push({
       uri: makeURI("http://example.com/autocomplete/?" + i),
     });
   });
--- a/browser/base/content/test/general/browser_windowactivation.js
+++ b/browser/base/content/test/general/browser_windowactivation.js
@@ -79,16 +79,24 @@ function test() {
 
   window.messageManager.addMessageListener("Test:FocusReceived", function(message) {
     // No color change should occur after a tab switch.
     if (colorChangeNotifications == 6) {
       sendGetBackgroundRequest(false);
     }
   });
 
+  window.messageManager.addMessageListener("Test:ActivateEvent", function(message) {
+    ok(message.data.ok, "Test:ActivateEvent");
+  });
+
+  window.messageManager.addMessageListener("Test:DeactivateEvent", function(message) {
+    ok(message.data.ok, "Test:DeactivateEvent");
+  });
+
   browser1.addEventListener("load", check, true);
   browser2.addEventListener("load", check, true);
   browser1.contentWindow.location = testPage;
   browser2.contentWindow.location = testPage;
 
   browser1.messageManager.loadFrameScript("data:,(" + childFunction.toString() + ")();", true);
   browser2.messageManager.loadFrameScript("data:,(" + childFunction.toString() + ")();", true);
 
@@ -127,16 +135,35 @@ function childFunction()
     expectingResponse = true;
     ifChanged = message.data.ifChanged;
   });
 
   content.addEventListener("focus", function () {
     sendAsyncMessage("Test:FocusReceived", { });
   }, false);
 
+  var windowGotActivate = false;
+  var windowGotDeactivate = false;
+  addEventListener("activate", function() {
+      sendAsyncMessage("Test:ActivateEvent", { ok: !windowGotActivate });
+      windowGotActivate = false;
+    });
+  
+  addEventListener("deactivate", function() {
+      sendAsyncMessage("Test:DeactivateEvent", { ok: !windowGotDeactivate });
+      windowGotDeactivate = false;
+    });
+  content.addEventListener("activate", function() {
+      windowGotActivate = true;;
+    });
+  
+  content.addEventListener("deactivate", function() {
+      windowGotDeactivate = true;
+    });
+
   content.setInterval(function () {
     if (!expectingResponse) {
       return;
     }
 
     let area = content.document.getElementById("area");
     if (!area) {
       return; /* hasn't loaded yet */
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -379,50 +379,16 @@ function promiseHistoryClearedState(aURI
       callbackDone();
     });
   });
 
   return deferred.promise;
 }
 
 /**
- * Allows waiting for an observer notification once.
- *
- * @param topic
- *        Notification topic to observe.
- *
- * @return {Promise}
- * @resolves The array [subject, data] from the observed notification.
- * @rejects Never.
- */
-function promiseTopicObserved(topic)
-{
-  let deferred = Promise.defer();
-  info("Waiting for observer topic " + topic);
-  Services.obs.addObserver(function PTO_observe(subject, topic, data) {
-    Services.obs.removeObserver(PTO_observe, topic);
-    deferred.resolve([subject, data]);
-  }, topic, false);
-  return deferred.promise;
-}
-
-/**
- * Clears history asynchronously.
- *
- * @return {Promise}
- * @resolves When history has been cleared.
- * @rejects Never.
- */
-function promiseClearHistory() {
-  let promise = promiseTopicObserved(PlacesUtils.TOPIC_EXPIRATION_FINISHED);
-  PlacesUtils.bhistory.removeAllPages();
-  return promise;
-}
-
-/**
  * Waits for the next top-level document load in the current browser.  The URI
  * of the document is compared against aExpectedURL.  The load is then stopped
  * before it actually starts.
  *
  * @param aExpectedURL
  *        The URL of the document that is expected to load.
  * @return promise
  */
--- a/browser/base/content/test/newtab/head.js
+++ b/browser/base/content/test/newtab/head.js
@@ -5,21 +5,22 @@ const PREF_NEWTAB_ENABLED = "browser.new
 const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directory.source";
 
 Services.prefs.setBoolPref(PREF_NEWTAB_ENABLED, true);
 
 let tmp = {};
 Cu.import("resource://gre/modules/Promise.jsm", tmp);
 Cu.import("resource://gre/modules/NewTabUtils.jsm", tmp);
 Cu.import("resource:///modules/DirectoryLinksProvider.jsm", tmp);
+Cu.import("resource://testing-common/PlacesTestUtils.jsm", tmp);
 Cc["@mozilla.org/moz/jssubscript-loader;1"]
   .getService(Ci.mozIJSSubScriptLoader)
   .loadSubScript("chrome://browser/content/sanitize.js", tmp);
 Cu.import("resource://gre/modules/Timer.jsm", tmp);
-let {Promise, NewTabUtils, Sanitizer, clearTimeout, setTimeout, DirectoryLinksProvider} = tmp;
+let {Promise, NewTabUtils, Sanitizer, clearTimeout, setTimeout, DirectoryLinksProvider, PlacesTestUtils} = tmp;
 
 let uri = Services.io.newURI("about:newtab", null, null);
 let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
 
 let isMac = ("nsILocalFileMac" in Ci);
 let isLinux = ("@mozilla.org/gnome-gconf-service;1" in Cc);
 let isWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
 let gWindow = window;
@@ -149,17 +150,17 @@ let TestRunner = {
     }
   },
 
   /**
    * Finishes all tests and cleans up.
    */
   finish: function () {
     function cleanupAndFinish() {
-      clearHistory(function () {
+      PlacesTestUtils.clearHistory().then(() => {
         whenPagesUpdated(finish);
         NewTabUtils.restore();
       });
     }
 
     let callbacks = NewTabUtils.links._populateCallbacks;
     let numCallbacks = callbacks.length;
 
@@ -224,36 +225,27 @@ function setLinks(aLinks, aCallback = Te
     });
   }
 
   // Call populateCache() once to make sure that all link fetching that is
   // currently in progress has ended. We clear the history, fill it with the
   // given entries and call populateCache() now again to make sure the cache
   // has the desired contents.
   NewTabUtils.links.populateCache(function () {
-    clearHistory(function () {
+    PlacesTestUtils.clearHistory().then(() => {
       fillHistory(links, function () {
         NewTabUtils.links.populateCache(function () {
           NewTabUtils.allPages.update();
           aCallback();
         }, true);
       });
     });
   });
 }
 
-function clearHistory(aCallback) {
-  Services.obs.addObserver(function observe(aSubject, aTopic, aData) {
-    Services.obs.removeObserver(observe, aTopic);
-    executeSoon(aCallback);
-  }, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
-
-  PlacesUtils.history.removeAllPages();
-}
-
 function fillHistory(aLinks, aCallback = TestRunner.next) {
   let numLinks = aLinks.length;
   if (!numLinks) {
     if (aCallback)
       executeSoon(aCallback);
     return;
   }
 
--- a/browser/base/content/test/social/browser.ini
+++ b/browser/base/content/test/social/browser.ini
@@ -26,16 +26,17 @@ support-files =
   social_worker.js
   unchecked.jpg
 
 [browser_aboutHome_activation.js]
 skip-if = e10s # Bug 1053965 "cw.ensureSnippetsMapThen is not a function", also see general/browser.ini about:home comments
 [browser_addons.js]
 [browser_blocklist.js]
 [browser_share.js]
+skip-if = true # bug 1115131
 [browser_social_activation.js]
 skip-if = e10s # Bug 933103 synthesizeMouseAtCenter not e10s friendly
 [browser_social_chatwindow.js]
 [browser_social_chatwindow_resize.js]
 [browser_social_chatwindowfocus.js]
 skip-if = e10s # tab crash on data url used in this test
 [browser_social_contextmenu.js]
 skip-if = e10s # Bug 1072669 context menu relies on target element
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -2206,17 +2206,16 @@
             Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT;
         ]]></getter>
       </property>
       <constructor><![CDATA[
         // default title
         _doorhangerTitle.value =
           gNavigatorBundle.getFormattedString(
             "badContentBlocked.notblocked.message", [this._brandShortName]);
-
         if (this.notification.options.state &
             Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT) {
           _doorhangerTitle.value =
             gNavigatorBundle.getFormattedString(
               "badContentBlocked.blocked.message", [this._brandShortName]);
           _mixedContent.hidden = false;
           _mixedContentUnblock.hidden = false;
           _mixedContentHelpLink.href =
@@ -2247,16 +2246,20 @@
             Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT) {
           this.setAttribute("trackingblockdisabled", true);
           _trackingContent.hidden = false;
           _trackingContentBlock.hidden = false;
           _trackingContentHelpLink.href =
             Services.urlFormatter.formatURLPref("app.support.baseURL")
               + "tracking-protection";
         }
+        if (Services.prefs.getBoolPref("privacy.trackingprotection.enabled")) {
+          let histogram = Services.telemetry.getHistogramById("TRACKING_PROTECTION_EVENTS");
+          histogram.add(0);
+        }
       ]]></constructor>
       <method name="disableMixedContentProtection">
         <body><![CDATA[
           // Use telemetry to measure how often unblocking happens
           const kMIXED_CONTENT_UNBLOCK_EVENT = 2;
           let histogram =
             Services.telemetry.getHistogramById(
               "MIXED_CONTENT_UNBLOCK_COUNTER");
@@ -2278,31 +2281,31 @@
           // convert document URI into the format used by
           // nsChannelClassifier::ShouldEnableTrackingProtection
           // (any scheme turned into https is correct)
           let normalizedUrl = Services.io.newURI(
             "https://" + gBrowser.selectedBrowser.currentURI.hostPort,
             null, null);
           // Add the current host in the 'trackingprotection' consumer of
           // the permission manager using a normalized URI. This effectively
-          // places this host on the tracking protection white list.
+          // places this host on the tracking protection allowlist.
           Services.perms.add(normalizedUrl,
             "trackingprotection", Services.perms.ALLOW_ACTION);
           // Telemetry for disable protection
           let histogram = Services.telemetry.getHistogramById(
               "TRACKING_PROTECTION_EVENTS");
           histogram.add(1);
           BrowserReload();
         ]]></body>
       </method>
       <method name="enableTrackingContentProtection">
         <body><![CDATA[
           // Remove the current host from the 'trackingprotection' consumer
           // of the permission manager. This effectively removes this host
-          // from the tracking protection white list (any list actually).
+          // from the tracking protection allowlist.
           Services.perms.remove(gBrowser.selectedBrowser.currentURI.host,
             "trackingprotection");
           // Telemetry for enable protection
           let histogram = Services.telemetry.getHistogramById(
               "TRACKING_PROTECTION_EVENTS");
           histogram.add(2);
           BrowserReload();
         ]]></body>
--- a/browser/components/customizableui/test/browser_967000_button_sync.js
+++ b/browser/components/customizableui/test/browser_967000_button_sync.js
@@ -17,18 +17,18 @@ function openAboutAccountsFromMenuPanel(
 
   // add the Sync button to the panel
   CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
 
   // check the button's functionality
   yield PanelUI.show();
 
   if (entryPoint == "uitour") {
-    UITour.originTabs.set(window, new Set());
-    UITour.originTabs.get(window).add(gBrowser.selectedTab);
+    UITour.tourBrowsersByWindow.set(window, new Set());
+    UITour.tourBrowsersByWindow.get(window).add(gBrowser.selectedBrowser);
   }
 
   let syncButton = document.getElementById("sync-button");
   ok(syncButton, "The Sync button was added to the Panel Menu");
 
   let deferred = Promise.defer();
   let handler = (e) => {
     if (e.originalTarget != gBrowser.selectedBrowser.contentDocument ||
@@ -60,16 +60,16 @@ function asyncCleanup() {
   Services.prefs.clearUserPref("identity.fxaccounts.remote.signup.uri");
   // reset the panel UI to the default state
   yield resetCustomization();
   ok(CustomizableUI.inDefaultState, "The panel UI is in default state again.");
 
   // restore the tabs
   gBrowser.addTab(initialLocation);
   gBrowser.removeTab(newTab);
-  UITour.originTabs.delete(window);
+  UITour.tourBrowsersByWindow.delete(window);
 }
 
 add_task(() => openAboutAccountsFromMenuPanel("syncbutton"));
 add_task(asyncCleanup);
 // Test that uitour is in progress, the entrypoint is `uitour` and not `menupanel`
 add_task(() => openAboutAccountsFromMenuPanel("uitour"));
 add_task(asyncCleanup);
--- a/browser/components/loop/standalone/content/index.html
+++ b/browser/components/loop/standalone/content/index.html
@@ -8,16 +8,27 @@
     <meta name="locales" content="en-US" />
     <meta name="default_locale" content="en-US" />
 
     <link rel="stylesheet" type="text/css" href="shared/css/reset.css">
     <link rel="stylesheet" type="text/css" href="shared/css/common.css">
     <link rel="stylesheet" type="text/css" href="shared/css/conversation.css">
     <link rel="stylesheet" type="text/css" href="css/webapp.css">
     <link rel="localization" href="l10n/{locale}/loop.properties">
+
+    <script>
+      (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+        m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+      })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+      ga('create', 'UA-36116321-15', 'auto');
+      ga('send', 'pageview');
+    </script>
+
   </head>
   <body class="standalone">
 
     <div id="main"></div>
 
     <!-- libs -->
     <script>
       // IE9, 10, and 11 lack the window.CustomEvent constructor. IE11 has the
--- a/browser/components/loop/standalone/content/js/webapp.js
+++ b/browser/components/loop/standalone/content/js/webapp.js
@@ -14,16 +14,17 @@ loop.webapp = (function($, _, OT, mozL10
   loop.config = loop.config || {};
   loop.config.serverUrl = loop.config.serverUrl || "http://localhost:5000";
 
   var sharedActions = loop.shared.actions;
   var sharedMixins = loop.shared.mixins;
   var sharedModels = loop.shared.models;
   var sharedViews = loop.shared.views;
   var sharedUtils = loop.shared.utils;
+  var WEBSOCKET_REASONS = loop.shared.utils.WEBSOCKET_REASONS;
 
   var multiplexGum = loop.standaloneMedia.multiplexGum;
 
   /**
    * Homepage view.
    */
   var HomeView = React.createClass({displayName: "HomeView",
     render: function() {
@@ -887,17 +888,17 @@ loop.webapp = (function($, _, OT, mozL10
      * Handles call rejection.
      *
      * @param {String} reason The reason the call was terminated (reject, busy,
      *                        timeout, cancel, media-fail, user-unknown, closed)
      */
     _handleCallTerminated: function(reason) {
       multiplexGum.reset();
 
-      if (reason === "cancel") {
+      if (reason === WEBSOCKET_REASONS.CANCEL) {
         this.setState({callStatus: "start"});
         return;
       }
       // XXX later, we'll want to display more meaningfull messages (needs UX)
       this.props.notifications.errorL10n("call_timeout_notification_text");
       this.setState({callStatus: "failure"});
     },
 
--- a/browser/components/loop/test/functional/config.py
+++ b/browser/components/loop/test/functional/config.py
@@ -2,17 +2,17 @@
 CONTENT_SERVER_PORT = 3001
 LOOP_SERVER_PORT = 5001
 FIREFOX_PREFERENCES = {
     "loop.server": "http://localhost:" + str(LOOP_SERVER_PORT),
     "browser.dom.window.dump.enabled": True,
     # Some more changes might be necesarry to have this working in offline mode
     "media.peerconnection.default_iceservers": "[]",
     "media.peerconnection.use_document_iceservers": False,
-    "stun.allow_loopback": True,
+    "media.peerconnection.ice.loopback": True,
     "devtools.chrome.enabled": True,
     "devtools.debugger.prompt-connection": False,
     "devtools.debugger.remote-enabled": True,
     "media.volume_scale": "0",
     "loop.gettingStarted.seen": True,
     "loop.seenToS": "seen",
 
     # this dialog is fragile, and likely to introduce intermittent failures
--- a/browser/components/loop/test/functional/test_1_browser_call.py
+++ b/browser/components/loop/test/functional/test_1_browser_call.py
@@ -5,16 +5,18 @@ from errors import NoSuchElementExceptio
 # noinspection PyUnresolvedReferences
 from wait import Wait
 from time import sleep
 
 import os
 import sys
 sys.path.insert(1, os.path.dirname(os.path.abspath(__file__)))
 
+import pyperclip
+
 from serversetup import LoopTestServers
 from config import *
 
 
 class Test1BrowserCall(MarionetteTestCase):
     # XXX Move this to setup class so it doesn't restart the server
     # after every test.
     def setUp(self):
@@ -34,114 +36,144 @@ class Test1BrowserCall(MarionetteTestCas
     # taken from https://github.com/mozilla-b2g/gaia/blob/master/tests/python/gaia-ui-tests/gaiatest/gaia_test.py#L858
     # XXX factor out into utility object for use by other tests
     def wait_for_element_displayed(self, by, locator, timeout=None):
         Wait(self.marionette, timeout,
              ignored_exceptions=[NoSuchElementException, StaleElementException])\
             .until(lambda m: m.find_element(by, locator).is_displayed())
         return self.marionette.find_element(by, locator)
 
-    # XXX workaround for Marionette bug 1055309
+    def wait_for_subelement_displayed(self, parent, by, locator, timeout=None):
+        Wait(self.marionette, timeout,
+             ignored_exceptions=[NoSuchElementException, StaleElementException])\
+            .until(lambda m: parent.find_element(by, locator).is_displayed())
+        return parent.find_element(by, locator)
+
+    # XXX workaround for Marionette bug 1094246
     def wait_for_element_exists(self, by, locator, timeout=None):
         Wait(self.marionette, timeout,
              ignored_exceptions=[NoSuchElementException, StaleElementException]) \
             .until(lambda m: m.find_element(by, locator))
         return self.marionette.find_element(by, locator)
 
+    def wait_for_element_enabled(self, element, timeout=10):
+        Wait(self.marionette, timeout) \
+            .until(lambda e: element.is_enabled(),
+                   message="Timed out waiting for element to be enabled")
+
+    def wait_for_element_attribute_to_be_false(self, element, attribute, timeout=10):
+        Wait(self.marionette, timeout) \
+            .until(lambda e: element.get_attribute(attribute) == "false",
+                   message="Timeout out waiting for " + attribute + " to be false")
+
     def switch_to_panel(self):
         button = self.marionette.find_element(By.ID, "loop-button")
 
         # click the element
         button.click()
 
         # switch to the frame
         frame = self.marionette.find_element(By.ID, "loop-panel-iframe")
         self.marionette.switch_to_frame(frame)
 
-    def load_and_verify_standalone_ui(self, url):
-        self.marionette.set_context("content")
-        self.marionette.navigate(url)
-
-    def start_a_conversation(self):
-        # TODO: wait for react elements
-        sleep(2)
-        button = self.marionette.find_element(By.CSS_SELECTOR, ".rooms .btn-info")
-
-        # click the element
-        button.click()
-
-    def get_and_verify_call_url(self):
-        # in the new room model we have to first start a conversation
-        self.start_a_conversation()
-
-        # TODO: wait for react elements
-        sleep(2)
-        call_url = self.marionette.find_element(By.CLASS_NAME, \
-                                                "room-url-link").text
-
-        self.assertIn(urlparse.urlparse(call_url).scheme, ['http', 'https'],
-                      "call URL returned by server " + call_url +
-                      " has invalid scheme")
-        return call_url
-
-    def start_and_verify_outgoing_call(self):
-        # TODO: wait for react elements
-        sleep(2)
-        # make the call!
-        call_button = self.marionette.find_element(By.CLASS_NAME,
-                                                   "btn-join")
-        call_button.click()
-
-    def accept_and_verify_incoming_call(self):
+    def switch_to_chatbox(self):
         self.marionette.set_context("chrome")
         self.marionette.switch_to_frame()
 
         # XXX should be using wait_for_element_displayed, but need to wait
-        # for Marionette bug 1055309 to be fixed.
+        # for Marionette bug 1094246 to be fixed.
         chatbox = self.wait_for_element_exists(By.TAG_NAME, 'chatbox')
         script = ("return document.getAnonymousElementByAttribute("
                   "arguments[0], 'class', 'chat-frame');")
         frame = self.marionette.execute_script(script, [chatbox])
         self.marionette.switch_to_frame(frame)
 
+    def switch_to_standalone(self):
+        self.marionette.set_context("content")
+
+    def local_start_a_conversation(self):
+        button = self.marionette.find_element(By.CSS_SELECTOR, ".rooms .btn-info")
+
+        self.wait_for_element_enabled(button, 120)
+
+        button.click()
+
+    def local_check_room_self_video(self):
+        self.switch_to_chatbox()
+
         # expect a video container on desktop side
-        video = self.wait_for_element_displayed(By.CLASS_NAME, "media")
-        self.assertEqual(video.tag_name, "div", "expect a video container")
+        media_container = self.wait_for_element_displayed(By.CLASS_NAME, "media")
+        self.assertEqual(media_container.tag_name, "div", "expect a video container")
+
+    def local_get_and_verify_room_url(self):
+        button = self.wait_for_element_displayed(By.CLASS_NAME, "btn-copy")
+
+        button.click()
+
+        # click the element
+        room_url = pyperclip.paste()
+
+        self.assertIn(urlparse.urlparse(room_url).scheme, ['http', 'https'],
+                      "room URL returned by server " + room_url +
+                      " has invalid scheme")
+        return room_url
+
+    def standalone_load_and_join_room(self, url):
+        self.switch_to_standalone()
+        self.marionette.navigate(url)
 
-    def hangup_call_and_verify_feedback(self):
-        self.marionette.set_context("chrome")
+        # Join the room
+        join_button = self.wait_for_element_displayed(By.CLASS_NAME,
+                                                      "btn-join")
+        join_button.click()
+
+    # Assumes the standlone or the conversation window is selected first.
+    def check_remote_video(self):
+        # TODO: This is disabled currently due to bug 1122486
+        # video_wrapper = self.wait_for_element_displayed(By.CSS_SELECTOR, ".media .OT_subscriber .OT_video-container", 20)
+        # video = self.wait_for_subelement_displayed(video_wrapper, By.TAG_NAME, "video")
+
+        # self.wait_for_element_attribute_to_be_false(video, "paused")
+        # self.assertEqual(video.get_attribute("ended"), "false")
+
+        # Due to the above waits being disabled, we do a sleep.
+        sleep(15)
+
+    def standalone_check_remote_video(self):
+        self.switch_to_standalone()
+        self.check_remote_video()
+
+    def local_check_remote_video(self):
+        self.switch_to_chatbox()
+        self.check_remote_video()
+
+    def local_leave_room_and_verify_feedback(self):
         button = self.marionette.find_element(By.CLASS_NAME, "btn-hangup")
 
-        # XXX bug 1080095 For whatever reason, the click doesn't take effect
-        # unless we wait for a bit (even if we wait for the element to
-        # actually be displayed first, which we're not currently bothering
-        # with).  It's not entirely clear whether the click is being
-        # delivered in this case, or whether there's a Marionette bug here.
-        sleep(5)
         button.click()
 
         # check that the feedback form is displayed
         feedback_form = self.wait_for_element_displayed(By.CLASS_NAME, "faces")
         self.assertEqual(feedback_form.tag_name, "div", "expect feedback form")
 
     def test_1_browser_call(self):
         self.switch_to_panel()
 
-        call_url = self.get_and_verify_call_url()
+        self.local_start_a_conversation()
+
+        # Check the self video in the conversation window
+        self.local_check_room_self_video()
+
+        room_url = self.local_get_and_verify_room_url()
 
         # load the link clicker interface into the current content browser
-        self.load_and_verify_standalone_ui(call_url)
-
-        self.start_and_verify_outgoing_call()
+        self.standalone_load_and_join_room(room_url)
 
-        # Switch to the conversation window and answer
-        self.accept_and_verify_incoming_call()
-
-        # Let's wait for the call/media to get established.
-        # TODO: replace this with some media detection
-        sleep(5)
+        # Check we get the video streams
+        self.standalone_check_remote_video()
+        self.local_check_remote_video()
 
         # hangup the call
-        self.hangup_call_and_verify_feedback()
+        self.local_leave_room_and_verify_feedback()
 
     def tearDown(self):
         self.loop_test_servers.shutdown()
         MarionetteTestCase.tearDown(self)
--- a/browser/components/places/tests/browser/browser_410196_paste_into_tags.js
+++ b/browser/components/places/tests/browser/browser_410196_paste_into_tags.js
@@ -52,17 +52,17 @@ function onClipboardReady() {
 
   // Remove new Places data we created.
   PlacesUtils.tagging.untagURI(NetUtil.newURI(MOZURISPEC), ["foo"]);
   PlacesUtils.tagging.untagURI(NetUtil.newURI(TEST_URL), ["foo"]);
   let tags = PlacesUtils.tagging.getTagsForURI(NetUtil.newURI(TEST_URL));
   is(tags.length, 0, "tags are gone");
   PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
 
-  waitForClearHistory(finish);
+  PlacesTestUtils.clearHistory().then(finish);
 }
 
 let tests = {
 
   makeHistVisit: function(aCallback) {
     // need to add a history object
     let testURI1 = NetUtil.newURI(MOZURISPEC);
     isnot(testURI1, null, "testURI is not null");
--- a/browser/components/places/tests/browser/browser_bookmarksProperties.js
+++ b/browser/components/places/tests/browser/browser_bookmarksProperties.js
@@ -469,18 +469,17 @@ gTests.push({
   },
 
   finish: function() {
     toggleSidebar(this.sidebar, false);
     runNextTest();
   },
 
   cleanup: function() {
-    var bh = PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory);
-    bh.removeAllPages();
+    return PlacesTestUtils.clearHistory();
   }
 });
 
 //------------------------------------------------------------------------------
 
 function test() {
   waitForExplicitFinish();
   // This test can take some time, if we timeout too early it could run
@@ -493,20 +492,21 @@ function test() {
 
   // kick off tests
   runNextTest();
 }
 
 function runNextTest() {
   // Cleanup from previous test.
   if (gCurrentTest) {
-    gCurrentTest.cleanup();
-    info("End of test: " + gCurrentTest.desc);
-    gCurrentTest = null;
-    waitForAsyncUpdates(runNextTest);
+    Promise.resolve(gCurrentTest.cleanup()).then(() => {
+      info("End of test: " + gCurrentTest.desc);
+      gCurrentTest = null;
+      waitForAsyncUpdates(runNextTest);
+    });
     return;
   }
 
   if (gTests.length > 0) {
     // Goto next tests.
     gCurrentTest = gTests.shift();
     info("Start of test: " + gCurrentTest.desc);
     gCurrentTest.setup(function() {
--- a/browser/components/places/tests/browser/browser_forgetthissite_single.js
+++ b/browser/components/places/tests/browser/browser_forgetthissite_single.js
@@ -15,17 +15,17 @@ function test() {
   TEST_URIs.forEach(function(TEST_URI) {
     places.push({uri: PlacesUtils._uri(TEST_URI),
                  transition: PlacesUtils.history.TRANSITION_TYPED});
   });
   addVisits(places, window, function() {
     testForgetThisSiteVisibility(1, function() {
       testForgetThisSiteVisibility(2, function() {
         // Cleanup
-        waitForClearHistory(finish);
+        PlacesTestUtils.clearHistory().then(finish);
       });
     });
   });
 
   function testForgetThisSiteVisibility(selectionCount, funcNext) {
     openLibrary(function (organizer) {
           // Select History in the left pane.
           organizer.PlacesOrganizer.selectLeftPaneQuery('History');
--- a/browser/components/places/tests/browser/browser_history_sidebar_search.js
+++ b/browser/components/places/tests/browser/browser_history_sidebar_search.js
@@ -26,17 +26,17 @@ var pages = [
 ];
 // Number of pages that will be filtered out by the search.
 const FILTERED_COUNT = 1;
 
 function test() {
   waitForExplicitFinish();
 
   // Cleanup.
-  waitForClearHistory(continue_test);
+  PlacesTestUtils.clearHistory().then(continue_test);
 }
 
 function continue_test() {
   // Add some visited page.
   var time = Date.now();
   var pagesLength = pages.length;
   var places = [];
   for (var i = 0; i < pagesLength; i++) {
@@ -59,17 +59,17 @@ function continue_test() {
       searchBox.doCommand();
       check_sidebar_tree_order(pages.length - FILTERED_COUNT);
       searchBox.value = "";
       searchBox.doCommand();
       check_sidebar_tree_order(pages.length);
 
       // Cleanup.
       toggleSidebar("viewHistorySidebar", false);
-      waitForClearHistory(finish);
+      PlacesTestUtils.clearHistory().then(finish);
     });
   }, true);
 }
 
 function check_sidebar_tree_order(aExpectedRows) {
   var tree = sidebar.contentDocument.getElementById("historyTree");
   var treeView = tree.view;
   var rc = treeView.rowCount;
--- a/browser/components/places/tests/browser/browser_library_commands.js
+++ b/browser/components/places/tests/browser/browser_library_commands.js
@@ -7,17 +7,17 @@
 /**
  *  Test enabled commands in the left pane folder of the Library.
  */
 
 const TEST_URI = NetUtil.newURI("http://www.mozilla.org/");
 
 registerCleanupFunction(function* () {
   yield PlacesUtils.bookmarks.eraseEverything();
-  yield promiseClearHistory();
+  yield PlacesTestUtils.clearHistory();
 });
 
 add_task(function* test_date_container() {
   let library = yield promiseLibrary();
   info("Ensure date containers under History cannot be cut but can be deleted");
 
   yield promiseAddVisits(TEST_URI);
 
--- a/browser/components/places/tests/browser/browser_library_downloads.js
+++ b/browser/components/places/tests/browser/browser_library_downloads.js
@@ -47,17 +47,17 @@ function test() {
         let len = contentRoot.childCount;
         const TEST_URIS = ["http://ubuntu.org/", "http://google.com/"];
         for (let i = 0; i < len; i++) {
           is(contentRoot.getChild(i).uri, TEST_URIS[i],
               "Comparing downloads shown at index " + i);
         }
 
         win.close();
-        waitForClearHistory(finish);
+        PlacesTestUtils.clearHistory().then(finish);
       }
     })
   }
 
   openLibrary(onLibraryReady, "Downloads");
 }
 
 function VisitInfo(aTransitionType)
--- a/browser/components/places/tests/browser/browser_library_infoBox.js
+++ b/browser/components/places/tests/browser/browser_library_infoBox.js
@@ -103,17 +103,17 @@ gTests.push({
       checkInfoBoxSelected(PO);
       ok(!infoBoxExpanderWrapper.hidden,
          "Expander button is not hidden for bookmark item.");
       checkAddInfoFieldsNotCollapsed(PO);
       checkAddInfoFields(PO, "bookmark item");
 
       menuNode.containerOpen = false;
 
-      waitForClearHistory(nextTest);
+      PlacesTestUtils.clearHistory().then(nextTest);
     }
     // add a visit to browser history
     addVisits(
       { uri: PlacesUtils._uri(TEST_URI), visitDate: Date.now() * 1000,
         transition: PlacesUtils.history.TRANSITION_TYPED },
       window,
       addVisitsCallback);
   }
--- a/browser/components/places/tests/browser/browser_library_panel_leak.js
+++ b/browser/components/places/tests/browser/browser_library_panel_leak.js
@@ -34,17 +34,17 @@ function test() {
     let selection = contentTree.view.selection;
     selection.clearSelection();
     selection.rangedSelect(0, 0, true);
     // Check the panel is editing the history entry.
     is(organizer.gEditItemOverlay.itemId, -1, "Editing an history entry");
     // Close Library window.
     organizer.close();
     // Clean up history.
-    waitForClearHistory(finish);
+    PlacesTestUtils.clearHistory().then(finish);
   }
 
   waitForExplicitFinish();
   // Add an history entry.
   ok(PlacesUtils, "checking PlacesUtils, running in chrome context?");
   addVisits(
     {uri: PlacesUtils._uri(TEST_URI), visitDate: Date.now() * 1000,
       transition: PlacesUtils.history.TRANSITION_TYPED},
--- a/browser/components/places/tests/browser/browser_library_search.js
+++ b/browser/components/places/tests/browser/browser_library_search.js
@@ -152,17 +152,17 @@ function onLibraryAvailable() {
   testCases.forEach(function (aTest) aTest());
 
   gLibrary.close();
   gLibrary = null;
 
   // Cleanup.
   PlacesUtils.tagging.untagURI(PlacesUtils._uri(TEST_URL), ["dummyTag"]);
   PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
-  waitForClearHistory(finish);
+  PlacesTestUtils.clearHistory().then(finish);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 function test() {
   waitForExplicitFinish();
 
   // Sanity:
--- a/browser/components/places/tests/browser/browser_sidebarpanels_click.js
+++ b/browser/components/places/tests/browser/browser_sidebarpanels_click.js
@@ -63,17 +63,17 @@ function test() {
       sidebar.contentDocument.getElementById("byvisited").doCommand();
     },
     selectNode: function(tree) {
       tree.selectNode(tree.view.nodeForTreeIndex(0));
       is(tree.selectedNode.uri, TEST_URL, "The correct visit has been selected");
       is(tree.selectedNode.itemId, -1, "The selected node is not bookmarked");
     },
     cleanup: function(aCallback) {
-      waitForClearHistory(aCallback);
+      PlacesTestUtils.clearHistory().then(aCallback);
     },
     sidebarName: HISTORY_SIDEBAR_ID,
     treeName: HISTORY_SIDEBAR_TREE_ID,
     desc: "History sidebar test"
   });
 
   function testPlacesPanel(preFunc, postFunc) {
     currentTest.init(function() {
@@ -149,10 +149,10 @@ function test() {
                         function() {
                           runNextTest();
                         });
                       });
     }
   }
 
   // Ensure history is clean before starting the test.
-  waitForClearHistory(runNextTest);
+  PlacesTestUtils.clearHistory().then(runNextTest);
 }
--- a/browser/components/places/tests/browser/head.js
+++ b/browser/components/places/tests/browser/head.js
@@ -1,16 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
   "resource://gre/modules/Promise.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
+  "resource://testing-common/PlacesTestUtils.jsm");
 
 // We need to cache this before test runs...
 let cachedLeftPaneFolderIdGetter;
 let (getter = PlacesUIUtils.__lookupGetter__("leftPaneFolderId")) {
   if (!cachedLeftPaneFolderIdGetter && typeof(getter) == "function")
     cachedLeftPaneFolderIdGetter = getter;
 }
 // ...And restore it when test ends.
@@ -69,31 +71,16 @@ function promiseClipboard(aPopulateClipb
   waitForClipboard(function (aData) !!aData,
                    aPopulateClipboardFn,
                    function () { deferred.resolve(); },
                    aFlavor);
   return deferred.promise;
 }
 
 /**
- * Waits for completion of a clear history operation, before
- * proceeding with aCallback.
- *
- * @param aCallback
- *        Function to be called when done.
- */
-function waitForClearHistory(aCallback) {
-  Services.obs.addObserver(function observeCH(aSubject, aTopic, aData) {
-    Services.obs.removeObserver(observeCH, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
-    aCallback();
-  }, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
-  PlacesUtils.bhistory.removeAllPages();
-}
-
-/**
  * Waits for all pending async statements on the default connection, before
  * proceeding with aCallback.
  *
  * @param aCallback
  *        Function to be called when done.
  * @param aScope
  *        Scope for the callback.
  * @param aArguments
@@ -367,42 +354,8 @@ function promiseHistoryNotification(noti
     });
     PlacesUtils.history.addObserver(proxifiedObserver, false);
     let timeout = setTimeout(() => {
       PlacesUtils.history.removeObserver(proxifiedObserver, false);
       reject(new Error("Timed out while waiting for history notification"));
     }, 2000);
   });
 }
-
-/**
- * Clears history asynchronously.
- *
- * @return {Promise}
- * @resolves When history has been cleared.
- * @rejects Never.
- */
-function promiseClearHistory() {
-  let promise = promiseTopicObserved(PlacesUtils.TOPIC_EXPIRATION_FINISHED);
-  PlacesUtils.bhistory.removeAllPages();
-  return promise;
-}
-
-/**
- * Allows waiting for an observer notification once.
- *
- * @param topic
- *        Notification topic to observe.
- *
- * @return {Promise}
- * @resolves The array [subject, data] from the observed notification.
- * @rejects Never.
- */
-function promiseTopicObserved(topic)
-{
-  let deferred = Promise.defer();
-  info("Waiting for observer topic " + topic);
-  Services.obs.addObserver(function PTO_observe(subject, topic, data) {
-    Services.obs.removeObserver(PTO_observe, topic);
-    deferred.resolve([subject, data]);
-  }, topic, false);
-  return deferred.promise;
-}
--- a/browser/components/places/tests/chrome/head.js
+++ b/browser/components/places/tests/chrome/head.js
@@ -1,8 +1,16 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
+  "resource://testing-common/PlacesTestUtils.jsm");
+
 /**
  * Asynchronously adds visits to a page, invoking a callback function when done.
  *
  * @param aPlaceInfo
  *        Can be an nsIURI, in such a case a single LINK visit will be added.
  *        Otherwise can be an object describing the visit to add, or an array
  *        of these objects:
  *          { uri: nsIURI of the page,
@@ -48,22 +56,8 @@ function addVisits(aPlaceInfo, aCallback
       handleResult: function () {},
       handleCompletion: function UP_handleCompletion() {
         if (aCallback)
           aCallback();
       }
     }
   );
 }
-
-/**
- * Clears history invoking callback when done.
- */
-function waitForClearHistory(aCallback) {
-  const TOPIC_EXPIRATION_FINISHED = "places-expiration-finished";
-  Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
-    Services.obs.removeObserver(observer, TOPIC_EXPIRATION_FINISHED);
-    aCallback();
-  }, TOPIC_EXPIRATION_FINISHED, false);
-  Cc["@mozilla.org/browser/nav-history-service;1"]
-    .getService(Ci.nsINavHistoryService)
-    .QueryInterface(Ci.nsIBrowserHistory).removeAllPages();
-}
--- a/browser/components/places/tests/chrome/test_bug549192.xul
+++ b/browser/components/places/tests/chrome/test_bug549192.xul
@@ -40,17 +40,17 @@
      * Bug 549192
      * Ensures that history views are updated after deleting entries.
      */
 
     SimpleTest.waitForExplicitFinish();
 
     function runTest() {
       // The mochitest page is added to history.
-      waitForClearHistory(continue_test);
+      PlacesTestUtils.clearHistory().then(continue_test);
     }
 
     function continue_test() {
       // Add some visits.
       let vtime = Date.now() * 1000;
       const ttype = PlacesUtils.history.TRANSITION_TYPED;
       let places =
         [{ uri: Services.io.newURI("http://example.tld/", null, null),
@@ -101,15 +101,15 @@
             let node = tree.selectedNode;
             tree.controller.remove("Removing page");
             ok(treeView.treeIndexForNode(node) == Ci.nsINavHistoryResultTreeViewer.INDEX_INVISIBLE,
               node.uri + " removed.");
             ok(treeView.rowCount == rc - i - 1, "Rows count decreased");
           }
 
           // Cleanup.
-          waitForClearHistory(SimpleTest.finish);
+          PlacesTestUtils.clearHistory().then(SimpleTest.finish);
         });
       });
     }
 
   ]]></script>
 </window>
--- a/browser/components/places/tests/chrome/test_bug549491.xul
+++ b/browser/components/places/tests/chrome/test_bug549491.xul
@@ -43,17 +43,17 @@
      * Ensures that changing the details of places tree's root-node doesn't
      * throw.
      */
 
     SimpleTest.waitForExplicitFinish();
 
     function runTest() {
       // The mochitest page is added to history.
-      waitForClearHistory(continue_test);
+      PlacesTestUtils.clearHistory().then(continue_test);
     }
 
     function continue_test() {
       addVisits(
         {uri: Services.io.newURI("http://example.tld/", null, null),
           transition: PlacesUtils.history.TRANSITION_TYPED},
         function() {
           // Make a history query.
@@ -67,31 +67,14 @@
 
           let rootNode = tree.result.root;
           let obs = tree.view.QueryInterface(Ci.nsINavHistoryResultObserver);
           obs.nodeHistoryDetailsChanged(rootNode, rootNode.time, rootNode.accessCount);
           obs.nodeTitleChanged(rootNode, rootNode.title);
           ok(true, "No exceptions thrown");
 
           // Cleanup.
-          waitForClearHistory(SimpleTest.finish);
+          PlacesTestUtils.clearHistory().then(SimpleTest.finish);
         });
     }
 
-    /**
-     * Clears history invoking callback when done.
-     */
-    function waitForClearHistory(aCallback) {
-      const TOPIC_EXPIRATION_FINISHED = "places-expiration-finished";
-      let observer = {
-        observe: function(aSubject, aTopic, aData) {
-          Services.obs.removeObserver(this, TOPIC_EXPIRATION_FINISHED);
-          aCallback();
-        }
-      };
-      Services.obs.addObserver(observer, TOPIC_EXPIRATION_FINISHED, false);
-      let hs = Cc["@mozilla.org/browser/nav-history-service;1"].
-               getService(Ci.nsINavHistoryService);
-      hs.QueryInterface(Ci.nsIBrowserHistory).removeAllPages();
-   }
-
   ]]></script>
 </window>
--- a/browser/components/places/tests/chrome/test_treeview_date.xul
+++ b/browser/components/places/tests/chrome/test_treeview_date.xul
@@ -49,17 +49,17 @@
      *
      * Ensures that date in places treeviews is correctly formatted.
      */
 
     SimpleTest.waitForExplicitFinish();
 
     function runTest() {
       // The mochitest page is added to history.
-      waitForClearHistory(continue_test);
+      PlacesTestUtils.clearHistory().then(continue_test);
     }
 
     function continue_test() {
       var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
                getService(Ci.nsINavHistoryService);
       var bh = hs.QueryInterface(Ci.nsIBrowserHistory);
       var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
                getService(Ci.nsINavBookmarksService);
@@ -143,17 +143,17 @@
               case "visitCount":
                 is(text, 1, "Visit count is correct");
                 break;
             }
           }
         }
         // Cleanup.
         bs.removeItem(itemId);
-        waitForClearHistory(SimpleTest.finish);
+        PlacesTestUtils.clearHistory().then(SimpleTest.finish);
       }
 
       // Add a visit 1ms before midnight, a visit at midnight, and
       // a visit 1ms after midnight.
       addVisits(
         [{uri: uri("http://before.midnight.com/"),
            visitDate: (midnight.getTime() - 1) * 1000,
            transition: hs.TRANSITION_TYPED},
@@ -161,28 +161,11 @@
            visitDate: (midnight.getTime()) * 1000,
            transition: hs.TRANSITION_TYPED},
          {uri: uri("http://after.midnight.com/"),
            visitDate: (midnight.getTime() + 1) * 1000,
            transition: hs.TRANSITION_TYPED}],
         addVisitsCallback);
     }
 
-    /**
-     * Clears history invoking callback when done.
-     */
-    function waitForClearHistory(aCallback) {
-      const TOPIC_EXPIRATION_FINISHED = "places-expiration-finished";
-      let observer = {
-        observe: function(aSubject, aTopic, aData) {
-          Services.obs.removeObserver(this, TOPIC_EXPIRATION_FINISHED);
-          aCallback();
-        }
-      };
-      Services.obs.addObserver(observer, TOPIC_EXPIRATION_FINISHED, false);
-      let hs = Cc["@mozilla.org/browser/nav-history-service;1"].
-               getService(Ci.nsINavHistoryService);
-      hs.QueryInterface(Ci.nsIBrowserHistory).removeAllPages();
-   }
-
   ]]>
   </script>
 </window>
--- a/browser/components/preferences/tests/browser_chunk_permissions.js
+++ b/browser/components/preferences/tests/browser_chunk_permissions.js
@@ -1,12 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
 Components.utils.import("resource://gre/modules/NetUtil.jsm");
 Components.utils.import("resource://gre/modules/ForgetAboutSite.jsm");
 
 const ABOUT_PERMISSIONS_SPEC = "about:permissions";
 
 const TEST_URI_1 = NetUtil.newURI("http://mozilla.com/");
 const TEST_URI_2 = NetUtil.newURI("http://mozilla.org/");
 const TEST_URI_3 = NetUtil.newURI("http://wikipedia.org/");
@@ -59,17 +58,17 @@ function cleanUp() {
       Services.perms.remove(TEST_URI_2.host, type);
       Services.perms.remove(TEST_URI_3.host, type);
     }
   }
 }
 
 function runNextTest() {
   if (gTestIndex == tests.length) {
-    waitForClearHistory(finish);
+    PlacesTestUtils.clearHistory().then(finish);
     return;
   }
 
   let nextTest = tests[gTestIndex++];
   info(nextTest.desc);
 
   function preinit_observer() {
     Services.obs.removeObserver(preinit_observer, "browser-permissions-preinit");
@@ -131,20 +130,8 @@ var tests = [
     }
   }
 ];
 
 function getSiteItem(aHost) {
   return gBrowser.contentDocument.
                   querySelector(".site[value='" + aHost + "']");
 }
-
-// copied from toolkit/components/places/tests/head_common.js
-function waitForClearHistory(aCallback) {
-  let observer = {
-    observe: function(aSubject, aTopic, aData) {
-      Services.obs.removeObserver(this, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
-      aCallback();
-    }
-  };
-  Services.obs.addObserver(observer, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
-  PlacesUtils.bhistory.removeAllPages();
-}
--- a/browser/components/preferences/tests/browser_permissions.js
+++ b/browser/components/preferences/tests/browser_permissions.js
@@ -1,12 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
 Components.utils.import("resource://gre/modules/NetUtil.jsm");
 
 const ABOUT_PERMISSIONS_SPEC = "about:permissions";
 
 const TEST_URI_1 = NetUtil.newURI("http://mozilla.com/");
 const TEST_URI_2 = NetUtil.newURI("http://mozilla.org/");
 
 const TEST_PRINCIPAL_1 = Services.scriptSecurityManager.getNoAppCodebasePrincipal(TEST_URI_1);
@@ -76,17 +75,17 @@ function cleanUp() {
     }
   }
 
   gBrowser.removeTab(gBrowser.selectedTab);
 }
 
 function runNextTest() {
   if (gTestIndex == tests.length) {
-    waitForClearHistory(finish);
+    PlacesTestUtils.clearHistory().then(finish);
     return;
   }
 
   let nextTest = tests[gTestIndex++];
   info("[" + nextTest.name + "] running test");
   nextTest();
 }
 
@@ -270,17 +269,17 @@ var tests = [
        "are allowed");
 
     runNextTest();
   },
 
   function test_forget_site() {
     // click "Forget About This Site" button
     gBrowser.contentDocument.getElementById("forget-site-button").doCommand();
-    waitForClearHistory(function() {
+    PlacesTestUtils.clearHistory().then(() => {
       is(gSiteLabel.value, "", "site label cleared");
 
       let allSitesItem = gBrowser.contentDocument.getElementById("all-sites-item");
       is(gSitesList.selectedItem, allSitesItem,
          "all sites item selected after forgetting selected site");
 
       // check to make sure site is gone from sites list
       let testSiteItem = getSiteItem(TEST_URI_2.host);
@@ -324,20 +323,8 @@ function addWindowListener(aURL, aCallba
         domwindow.close();
         aCallback();
       }, domwindow);
     },
     onCloseWindow: function(aXULWindow) { },
     onWindowTitleChange: function(aXULWindow, aNewTitle) { }
   });
 }
-
-// copied from toolkit/components/places/tests/head_common.js
-function waitForClearHistory(aCallback) {
-  let observer = {
-    observe: function(aSubject, aTopic, aData) {
-      Services.obs.removeObserver(this, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
-      aCallback();
-    }
-  };
-  Services.obs.addObserver(observer, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
-  PlacesUtils.bhistory.removeAllPages();
-}
--- a/browser/components/preferences/tests/head.js
+++ b/browser/components/preferences/tests/head.js
@@ -1,10 +1,13 @@
 Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
+  "resource://testing-common/PlacesTestUtils.jsm");
+
 /**
  * Asynchronously adds visits to a page, invoking a callback function when done.
  *
  * @param aPlaceInfo
  *        Can be an nsIURI, in such a case a single LINK visit will be added.
  *        Otherwise can be an object describing the visit to add, or an array
  *        of these objects:
  *          { uri: nsIURI of the page,
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placesTitleNoUpdate.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placesTitleNoUpdate.js
@@ -26,17 +26,17 @@ function test() {
     PlacesUtils.history.removeObserver(historyObserver, false);
     windowsToClose.forEach(function(aWin) {
       aWin.close();
     });
     gBrowser.removeTab(tabToClose);
   });
 
 
-  waitForClearHistory(function () {
+  PlacesTestUtils.clearHistory().then(() => {
     historyObserver = {
       onTitleChanged: function(aURI, aPageTitle) {
         switch (++testNumber) {
           case 1:
             afterFirstVisit();
           break;
           case 2:
             afterUpdateVisit();
@@ -84,17 +84,17 @@ function test() {
       whenPageLoad(aWin, function() {
         executeSoon(afterFirstVisitInPrivateWindow);
       });
     });
   }
 
   function afterFirstVisitInPrivateWindow() {
      is(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_2, "The title remains the same after visiting in private window");
-     waitForClearHistory(finish);
+     PlacesTestUtils.clearHistory().then(finish);
   }
 
   function whenPageLoad(aWin, aCallback) {
     aWin.gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
       aWin.gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
       aCallback();
     }, true);
     aWin.gBrowser.selectedBrowser.loadURI(TEST_URL);
@@ -102,22 +102,10 @@ function test() {
 
   function testOnWindow(aPrivate, aCallback) {
     whenNewWindowLoaded({ private: aPrivate }, function(aWin) {
       selectedWin = aWin;
       windowsToClose.push(aWin);
       executeSoon(function() { aCallback(aWin) });
     });
   }
-
-  function waitForClearHistory(aCallback) {
-    let observer = {
-      observe: function(aSubject, aTopic, aData) {
-        Services.obs.removeObserver(this, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
-        aCallback();
-      }
-    };
-    Services.obs.addObserver(observer, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
-
-    PlacesUtils.bhistory.removeAllPages();
-  }
 }
 
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placestitle.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placestitle.js
@@ -11,21 +11,17 @@ function test() {
   const TEST_URL = "http://mochi.test:8888/browser/browser/components/" +
                    "privatebrowsing/test/browser/title.sjs";
   let cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager);
 
   function waitForCleanup(aCallback) {
     // delete all cookies
     cm.removeAll();
     // delete all history items
-    Services.obs.addObserver(function observeCH(aSubject, aTopic, aData) {
-      Services.obs.removeObserver(observeCH, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
-      aCallback();
-    }, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
-    PlacesUtils.bhistory.removeAllPages();
+    PlacesTestUtils.clearHistory().then(aCallback);
   }
 
   let testNumber = 0;
   let historyObserver = {
     onTitleChanged: function(aURI, aPageTitle) {
       if (aURI.spec != TEST_URL)
         return;
       switch (++testNumber) {
--- a/browser/components/privatebrowsing/test/browser/head.js
+++ b/browser/components/privatebrowsing/test/browser/head.js
@@ -1,11 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
+  "resource://testing-common/PlacesTestUtils.jsm");
+
 function whenNewWindowLoaded(aOptions, aCallback) {
   let win = OpenBrowserWindow(aOptions);
   let gotLoad = false;
   let gotActivate = Services.focus.activeWindow == win;
 
   function maybeRunCallback() {
     if (gotLoad && gotActivate) {
       executeSoon(function() { aCallback(win); });
--- a/browser/components/uitour/UITour-lib.js
+++ b/browser/components/uitour/UITour-lib.js
@@ -175,24 +175,16 @@ if (typeof Mozilla == 'undefined') {
 
 			callback(theme);
 		}
 
 		themeIntervalId = setInterval(nextTheme, delay);
 		nextTheme();
 	};
 
-	Mozilla.UITour.addPinnedTab = function() {
-		_sendEvent('addPinnedTab');
-	};
-
-	Mozilla.UITour.removePinnedTab = function() {
-		_sendEvent('removePinnedTab');
-	};
-
 	Mozilla.UITour.showMenu = function(name, callback) {
 		var showCallbackID;
 		if (callback)
 			showCallbackID = _waitForCallback(callback);
 
 		_sendEvent('showMenu', {
 			name: name,
 			showCallbackID: showCallbackID,
--- a/browser/components/uitour/UITour.jsm
+++ b/browser/components/uitour/UITour.jsm
@@ -24,16 +24,25 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
   "resource:///modules/BrowserUITelemetry.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Metrics",
   "resource://gre/modules/Metrics.jsm");
 
 // See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
 const PREF_LOG_LEVEL      = "browser.uitour.loglevel";
 const PREF_SEENPAGEIDS    = "browser.uitour.seenPageIDs";
+
+const BACKGROUND_PAGE_ACTIONS_ALLOWED = new Set([
+  "getConfiguration",
+  "getTreatmentTag",
+  "ping",
+  "registerPageID",
+  "setConfiguration",
+  "setTreatmentTag",
+]);
 const MAX_BUTTONS         = 4;
 
 const BUCKET_NAME         = "UITour";
 const BUCKET_TIMESTEPS    = [
   1 * 60 * 1000, // Until 1 minute after tab is closed/inactive.
   3 * 60 * 1000, // Until 3 minutes after tab is closed/inactive.
   10 * 60 * 1000, // Until 10 minutes after tab is closed/inactive.
   60 * 60 * 1000, // Until 1 hour after tab is closed/inactive.
@@ -54,30 +63,24 @@ XPCOMUtils.defineLazyGetter(this, "log",
     prefix: "UITour",
   };
   return new ConsoleAPI(consoleOptions);
 });
 
 this.UITour = {
   url: null,
   seenPageIDs: null,
-  pageIDSourceTabs: new WeakMap(),
-  pageIDSourceWindows: new WeakMap(),
-  /* Map from browser windows to a set of tabs in which a tour is open */
-  originTabs: new WeakMap(),
-  /* Map from browser windows to a set of pinned tabs opened by (a) tour(s) */
-  pinnedTabs: new WeakMap(),
+  pageIDSourceBrowsers: new WeakMap(),
+  /* Map from browser chrome windows to a Set of <browser>s in which a tour is open (both visible and hidden) */
+  tourBrowsersByWindow: new WeakMap(),
   urlbarCapture: new WeakMap(),
   appMenuOpenForAnnotation: new Set(),
   availableTargetsCache: new WeakMap(),
 
-  _detachingTab: false,
   _annotationPanelMutationObservers: new WeakMap(),
-  _queuedEvents: [],
-  _pendingDoc: null,
 
   highlightEffects: ["random", "wobble", "zoom", "color"],
   targets: new Map([
     ["accountStatus", {
       query: (aDocument) => {
         let statusButton = aDocument.getElementById("PanelUI-fxa-status");
         return aDocument.getAnonymousElementByAttribute(statusButton,
                                                         "class",
@@ -327,17 +330,17 @@ this.UITour = {
 
   onPageEvent: function(aMessage, aEvent) {
     let contentDocument = null;
     let browser = aMessage.target;
     let window = browser.ownerDocument.defaultView;
     let tab = window.gBrowser.getTabForBrowser(browser);
     let messageManager = browser.messageManager;
 
-    log.debug("onPageEvent:", aEvent.detail);
+    log.debug("onPageEvent:", aEvent.detail, aMessage);
 
     if (typeof aEvent.detail != "object") {
       log.warn("Malformed event - detail not an object");
       return false;
     }
 
     let action = aEvent.detail.action;
     if (typeof action != "string" || !action) {
@@ -346,33 +349,28 @@ this.UITour = {
     }
 
     let data = aEvent.detail.data;
     if (typeof data != "object") {
       log.warn("Malformed event - data not an object");
       return false;
     }
 
+    if ((aEvent.pageVisibilityState == "hidden" ||
+         aEvent.pageVisibilityState == "unloaded") &&
+        !BACKGROUND_PAGE_ACTIONS_ALLOWED.has(action)) {
+      log.warn("Ignoring disallowed action from a hidden page:", action);
+      return false;
+    }
+
     // Do this before bailing if there's no tab, so later we can pick up the pieces:
     window.gBrowser.tabContainer.addEventListener("TabSelect", this);
 
     if (!window.gMultiProcessBrowser) { // Non-e10s. See bug 1089000.
       contentDocument = browser.contentWindow.document;
-      if (!tab) {
-        // This should only happen while detaching a tab:
-        if (this._detachingTab) {
-          log.debug("Got event while detatching a tab");
-          this._queuedEvents.push(aEvent);
-          this._pendingDoc = Cu.getWeakReference(contentDocument);
-          return;
-        }
-        log.error("Discarding tabless UITour event (" + action + ") while not detaching a tab." +
-                       "This shouldn't happen!");
-        return;
-      }
     }
 
     switch (action) {
       case "registerPageID": {
         // This is only relevant if Telemtry is enabled.
         if (!UITelemetry.enabled) {
           log.debug("registerPageID: Telemery disabled, not doing anything");
           break;
@@ -382,22 +380,17 @@ this.UITour = {
         // pageID, as it could make parsing the telemetry bucket name difficult.
         if (typeof data.pageID != "string" ||
             data.pageID.contains(BrowserUITelemetry.BUCKET_SEPARATOR)) {
           log.warn("registerPageID: Invalid page ID specified");
           break;
         }
 
         this.addSeenPageID(data.pageID);
-
-        // Store tabs and windows separately so we don't need to loop over all
-        // tabs when a window is closed.
-        this.pageIDSourceTabs.set(tab, data.pageID);
-        this.pageIDSourceWindows.set(window, data.pageID);
-
+        this.pageIDSourceBrowsers.set(browser, data.pageID);
         this.setTelemetryBucket(data.pageID);
 
         break;
       }
 
       case "showHighlight": {
         let targetPromise = this.getTarget(window, data.target);
         targetPromise.then(target => {
@@ -480,26 +473,16 @@ this.UITour = {
         break;
       }
 
       case "resetTheme": {
         this.resetTheme();
         break;
       }
 
-      case "addPinnedTab": {
-        this.ensurePinnedTab(window, true);
-        break;
-      }
-
-      case "removePinnedTab": {
-        this.removePinnedTab(window);
-        break;
-      }
-
       case "showMenu": {
         this.showMenu(window, data.name, () => {
           if (typeof data.showCallbackID == "string")
             this.sendPageCallback(messageManager, data.showCallbackID);
         });
         break;
       }
 
@@ -645,111 +628,65 @@ this.UITour = {
 
       case "ping": {
         if (typeof data.callbackID == "string")
           this.sendPageCallback(messageManager, data.callbackID);
         break;
       }
     }
 
-    if (!window.gMultiProcessBrowser) { // Non-e10s. See bug 1089000.
-      if (!this.originTabs.has(window)) {
-        this.originTabs.set(window, new Set());
-      }
+    if (!this.tourBrowsersByWindow.has(window)) {
+      this.tourBrowsersByWindow.set(window, new Set());
+    }
+    this.tourBrowsersByWindow.get(window).add(browser);
 
-      this.originTabs.get(window).add(tab);
+    // We don't have a tab if we're in a <browser> without a tab.
+    if (tab) {
       tab.addEventListener("TabClose", this);
-      tab.addEventListener("TabBecomingWindow", this);
-      window.addEventListener("SSWindowClosing", this);
     }
 
+    window.addEventListener("SSWindowClosing", this);
+
     return true;
   },
 
   handleEvent: function(aEvent) {
+    log.debug("handleEvent: type =", aEvent.type, "event =", aEvent);
     switch (aEvent.type) {
       case "pagehide": {
         let window = this.getChromeWindow(aEvent.target);
-        this.teardownTour(window);
+        this.teardownTourForWindow(window);
         break;
       }
 
-      case "TabBecomingWindow":
-        this._detachingTab = true;
-        // Fall through
       case "TabClose": {
         let tab = aEvent.target;
-        if (this.pageIDSourceTabs.has(tab)) {
-          let pageID = this.pageIDSourceTabs.get(tab);
-
-          // Delete this from the window cache, so if the window is closed we
-          // don't expire this page ID twice.
-          let window = tab.ownerDocument.defaultView;
-          if (this.pageIDSourceWindows.get(window) == pageID)
-            this.pageIDSourceWindows.delete(window);
-
-          this.setExpiringTelemetryBucket(pageID, "closed");
-        }
-
         let window = tab.ownerDocument.defaultView;
-        this.teardownTour(window);
+        this.teardownTourForBrowser(window, tab.linkedBrowser, true);
         break;
       }
 
       case "TabSelect": {
+        let window = aEvent.target.ownerDocument.defaultView;
+
+        // Teardown the browser of the tab we just switched away from.
         if (aEvent.detail && aEvent.detail.previousTab) {
           let previousTab = aEvent.detail.previousTab;
-
-          if (this.pageIDSourceTabs.has(previousTab)) {
-            let pageID = this.pageIDSourceTabs.get(previousTab);
-            this.setExpiringTelemetryBucket(pageID, "inactive");
+          let openTourWindows = this.tourBrowsersByWindow.get(window);
+          if (openTourWindows.has(previousTab.linkedBrowser)) {
+            this.teardownTourForBrowser(window, previousTab.linkedBrowser, false);
           }
         }
 
-        let window = aEvent.target.ownerDocument.defaultView;
-        let selectedTab = window.gBrowser.selectedTab;
-        let pinnedTab = this.pinnedTabs.get(window);
-        if (pinnedTab && pinnedTab.tab == selectedTab)
-          break;
-        let originTabs = this.originTabs.get(window);
-        if (originTabs && originTabs.has(selectedTab))
-          break;
-
-        let pendingDoc;
-        if (this._detachingTab && this._pendingDoc && (pendingDoc = this._pendingDoc.get())) {
-          if (selectedTab.linkedBrowser.contentDocument == pendingDoc) {
-            if (!this.originTabs.get(window)) {
-              this.originTabs.set(window, new Set());
-            }
-            this.originTabs.get(window).add(selectedTab);
-            this.pendingDoc = null;
-            this._detachingTab = false;
-            while (this._queuedEvents.length) {
-              try {
-                this.onPageEvent(this._queuedEvents.shift());
-              } catch (ex) {
-                log.error(ex);
-              }
-            }
-            break;
-          }
-        }
-
-        this.teardownTour(window);
         break;
       }
 
       case "SSWindowClosing": {
         let window = aEvent.target;
-        if (this.pageIDSourceWindows.has(window)) {
-          let pageID = this.pageIDSourceWindows.get(window);
-          this.setExpiringTelemetryBucket(pageID, "closed");
-        }
-
-        this.teardownTour(window, true);
+        this.teardownTourForWindow(window);
         break;
       }
 
       case "input": {
         if (aEvent.target.id == "urlbar") {
           let window = aEvent.target.ownerDocument.defaultView;
           this.handleUrlbarInput(window);
         }
@@ -774,49 +711,83 @@ this.UITour = {
   // This is registered with UITelemetry by BrowserUITelemetry, so that UITour
   // can remain lazy-loaded on-demand.
   getTelemetry: function() {
     return {
       seenPageIDs: [...this.seenPageIDs.keys()],
     };
   },
 
-  teardownTour: function(aWindow, aWindowClosing = false) {
-    log.debug("teardownTour: aWindowClosing = " + aWindowClosing);
-    aWindow.gBrowser.tabContainer.removeEventListener("TabSelect", this);
-    aWindow.removeEventListener("SSWindowClosing", this);
+  /**
+   * Tear down a tour from a tab e.g. upon switching/closing tabs.
+   */
+  teardownTourForBrowser: function(aWindow, aBrowser, aTourPageClosing = false) {
+    log.debug("teardownTourForBrowser: aBrowser = ", aBrowser, aTourPageClosing);
 
-    let originTabs = this.originTabs.get(aWindow);
-    if (originTabs) {
-      for (let tab of originTabs) {
+    if (this.pageIDSourceBrowsers.has(aBrowser)) {
+      let pageID = this.pageIDSourceBrowsers.get(aBrowser);
+      this.setExpiringTelemetryBucket(pageID, aTourPageClosing ? "closed" : "inactive");
+    }
+
+    let openTourBrowsers = this.tourBrowsersByWindow.get(aWindow);
+    if (aTourPageClosing) {
+      let tab = aWindow.gBrowser.getTabForBrowser(aBrowser);
+      if (tab) { // Handle standalone <browser>
         tab.removeEventListener("TabClose", this);
-        tab.removeEventListener("TabBecomingWindow", this);
+        if (openTourBrowsers) {
+          openTourBrowsers.delete(aBrowser);
+        }
       }
     }
-    this.originTabs.delete(aWindow);
 
-    if (!aWindowClosing) {
-      this.hideHighlight(aWindow);
-      this.hideInfo(aWindow);
-      // Ensure the menu panel is hidden before calling recreatePopup so popup events occur.
-      this.hideMenu(aWindow, "appMenu");
-      this.hideMenu(aWindow, "loop");
-    }
+    this.hideHighlight(aWindow);
+    this.hideInfo(aWindow);
+    // Ensure the menu panel is hidden before calling recreatePopup so popup events occur.
+    this.hideMenu(aWindow, "appMenu");
+    this.hideMenu(aWindow, "loop");
 
-    // Clean up panel listeners after we may have called hideMenu above.
+    // Clean up panel listeners after calling hideMenu above.
     aWindow.PanelUI.panel.removeEventListener("popuphiding", this.hideAppMenuAnnotations);
     aWindow.PanelUI.panel.removeEventListener("ViewShowing", this.hideAppMenuAnnotations);
     aWindow.PanelUI.panel.removeEventListener("popuphidden", this.onPanelHidden);
     let loopPanel = aWindow.document.getElementById("loop-notification-panel");
     loopPanel.removeEventListener("popuphidden", this.onPanelHidden);
     loopPanel.removeEventListener("popuphiding", this.hideLoopPanelAnnotations);
 
     this.endUrlbarCapture(aWindow);
-    this.removePinnedTab(aWindow);
     this.resetTheme();
+
+    // If there are no more tour tabs left in the window, teardown the tour for the whole window.
+    if (!openTourBrowsers || openTourBrowsers.size == 0) {
+      this.teardownTourForWindow(aWindow);
+    }
+  },
+
+  /**
+   * Tear down all tours for a ChromeWindow.
+   */
+  teardownTourForWindow: function(aWindow) {
+    log.debug("teardownTourForWindow");
+    aWindow.gBrowser.tabContainer.removeEventListener("TabSelect", this);
+    aWindow.removeEventListener("SSWindowClosing", this);
+
+    let openTourBrowsers = this.tourBrowsersByWindow.get(aWindow);
+    if (openTourBrowsers) {
+      for (let browser of openTourBrowsers) {
+        if (this.pageIDSourceBrowsers.has(browser)) {
+          let pageID = this.pageIDSourceBrowsers.get(browser);
+          this.setExpiringTelemetryBucket(pageID, "closed");
+        }
+
+        let tab = aWindow.gBrowser.getTabForBrowser(browser);
+        tab.removeEventListener("TabClose", this);
+      }
+    }
+
+    this.tourBrowsersByWindow.delete(aWindow);
   },
 
   getChromeWindow: function(aContentDocument) {
     return aContentDocument.defaultView
                            .window
                            .QueryInterface(Ci.nsIInterfaceRequestor)
                            .getInterface(Ci.nsIWebNavigation)
                            .QueryInterface(Ci.nsIDocShellTreeItem)
@@ -870,24 +841,16 @@ this.UITour = {
     log.debug("getTarget:", aTargetName);
     let deferred = Promise.defer();
     if (typeof aTargetName != "string" || !aTargetName) {
       log.warn("getTarget: Invalid target name specified");
       deferred.reject("Invalid target name specified");
       return deferred.promise;
     }
 
-    if (aTargetName == "pinnedTab") {
-      deferred.resolve({
-          targetName: aTargetName,
-          node: this.ensurePinnedTab(aWindow, aSticky)
-      });
-      return deferred.promise;
-    }
-
     if (aTargetName.startsWith(TARGET_SEARCHENGINE_PREFIX)) {
       let engineID = aTargetName.slice(TARGET_SEARCHENGINE_PREFIX.length);
       return this.getSearchEngineTarget(aWindow, engineID);
     }
 
     let targetObject = this.targets.get(aTargetName);
     if (!targetObject) {
       log.warn("getTarget: The specified target name is not in the allowed set");
@@ -991,46 +954,16 @@ this.UITour = {
     if (data)
       LightweightThemeManager.previewTheme(data);
   },
 
   resetTheme: function() {
     LightweightThemeManager.resetPreview();
   },
 
-  ensurePinnedTab: function(aWindow, aSticky = false) {
-    let tabInfo = this.pinnedTabs.get(aWindow);
-
-    if (tabInfo) {
-      tabInfo.sticky = tabInfo.sticky || aSticky;
-    } else {
-      let url = Services.urlFormatter.formatURLPref("browser.uitour.pinnedTabUrl");
-
-      let tab = aWindow.gBrowser.addTab(url);
-      aWindow.gBrowser.pinTab(tab);
-      tab.addEventListener("TabClose", () => {
-        this.pinnedTabs.delete(aWindow);
-      });
-
-      tabInfo = {
-        tab: tab,
-        sticky: aSticky
-      };
-      this.pinnedTabs.set(aWindow, tabInfo);
-    }
-
-    return tabInfo.tab;
-  },
-
-  removePinnedTab: function(aWindow) {
-    let tabInfo = this.pinnedTabs.get(aWindow);
-    if (tabInfo)
-      aWindow.gBrowser.removeTab(tabInfo.tab);
-  },
-
   /**
    * @param aChromeWindow The chrome window that the highlight is in. Necessary since some targets
    *                      are in a sub-frame so the defaultView is not the same as the chrome
    *                      window.
    * @param aTarget    The element to highlight.
    * @param aEffect    (optional) The effect to use from UITour.highlightEffects or "none".
    * @see UITour.highlightEffects
    */
@@ -1122,20 +1055,16 @@ this.UITour = {
     }
 
     this._setAppMenuStateForAnnotation(aChromeWindow, "highlight",
                                        this.targetIsInAppMenu(aTarget),
                                        showHighlightPanel.bind(this));
   },
 
   hideHighlight: function(aWindow) {
-    let tabData = this.pinnedTabs.get(aWindow);
-    if (tabData && !tabData.sticky)
-      this.removePinnedTab(aWindow);
-
     let highlighter = aWindow.document.getElementById("UITourHighlight");
     this._removeAnnotationPanelMutationObserver(highlighter.parentElement);
     highlighter.parentElement.hidePopup();
     highlighter.removeAttribute("active");
 
     this._setAppMenuStateForAnnotation(aWindow, "highlight", false);
     this._hideSearchEngineHighlight(aWindow);
   },
@@ -1289,16 +1218,17 @@ this.UITour = {
     this._setAppMenuStateForAnnotation(aWindow, "info", false);
 
     let tooltipButtons = document.getElementById("UITourTooltipButtons");
     while (tooltipButtons.firstChild)
       tooltipButtons.firstChild.remove();
   },
 
   showMenu: function(aWindow, aMenuName, aOpenCallback = null) {
+    log.debug("showMenu:", aMenuName);
     function openMenuButton(aMenuBtn) {
       if (!aMenuBtn || !aMenuBtn.boxObject || aMenuBtn.open) {
         if (aOpenCallback)
           aOpenCallback();
         return;
       }
       if (aOpenCallback)
         aMenuBtn.addEventListener("popupshown", onPopupShown);
@@ -1353,16 +1283,17 @@ this.UITour = {
     } else if (aMenuName == "searchEngines") {
       this.getTarget(aWindow, "searchProvider").then(target => {
         openMenuButton(target.node);
       }).catch(log.error);
     }
   },
 
   hideMenu: function(aWindow, aMenuName) {
+    log.debug("hideMenu:", aMenuName);
     function closeMenuButton(aMenuBtn) {
       if (aMenuBtn && aMenuBtn.boxObject)
         aMenuBtn.boxObject.openMenu(false);
     }
 
     if (aMenuName == "appMenu") {
       aWindow.PanelUI.hide();
     } else if (aMenuName == "bookmarks") {
@@ -1524,20 +1455,17 @@ this.UITour = {
       }
 
       let promises = [];
       for (let targetName of this.targets.keys()) {
         promises.push(this.getTarget(window, targetName));
       }
       let targetObjects = yield Promise.all(promises);
 
-      let targetNames = [
-        "pinnedTab",
-      ];
-
+      let targetNames = [];
       for (let targetObject of targetObjects) {
         if (targetObject.node)
           targetNames.push(targetObject.targetName);
       }
 
       targetNames = targetNames.concat(
         yield this.getAvailableSearchEngineTargets(window)
       );
@@ -1685,22 +1613,26 @@ this.UITour = {
 
   notify(eventName, params) {
     let winEnum = Services.wm.getEnumerator("navigator:browser");
     while (winEnum.hasMoreElements()) {
       let window = winEnum.getNext();
       if (window.closed)
         continue;
 
-      let originTabs = this.originTabs.get(window);
-      if (!originTabs)
+      let openTourBrowsers = this.tourBrowsersByWindow.get(window);
+      if (!openTourBrowsers)
         continue;
 
-      for (let tab of originTabs) {
-        let messageManager = tab.linkedBrowser.messageManager;
+      for (let browser of openTourBrowsers) {
+        let messageManager = browser.messageManager;
+        if (!messageManager) {
+          log.error("notify: Trying to notify a browser without a messageManager", browser);
+          continue;
+        }
         let detail = {
           event: eventName,
           params: params,
         };
         messageManager.sendAsyncMessage("UITour:SendPageNotification", detail);
       }
     }
   },
--- a/browser/components/uitour/content-UITour.js
+++ b/browser/components/uitour/content-UITour.js
@@ -12,17 +12,21 @@ let UITourListener = {
     if (!Services.prefs.getBoolPref("browser.uitour.enabled")) {
       return;
     }
     if (!this.ensureTrustedOrigin()) {
       return;
     }
     addMessageListener("UITour:SendPageCallback", this);
     addMessageListener("UITour:SendPageNotification", this);
-    sendAsyncMessage("UITour:onPageEvent", {detail: event.detail, type: event.type});
+    sendAsyncMessage("UITour:onPageEvent", {
+      detail: event.detail,
+      type: event.type,
+      pageVisibilityState: content.document.visibilityState,
+    });
   },
 
   isTestingOrigin: function(aURI) {
     if (Services.prefs.getPrefType(PREF_TEST_WHITELIST) != Services.prefs.PREF_STRING) {
       return false;
     }
 
     // Add any testing origins (comma-seperated) to the whitelist for the session.
--- a/browser/components/uitour/test/browser.ini
+++ b/browser/components/uitour/test/browser.ini
@@ -4,18 +4,18 @@ support-files =
   image.png
   uitour.html
   ../UITour-lib.js
 
 [browser_UITour.js]
 skip-if = os == "linux" || e10s # Intermittent failures, bug 951965
 [browser_UITour2.js]
 skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
-[browser_UITour3.js]
-skip-if = os == "linux" || e10s # Linux: Bug 986760, Bug 989101; e10s: Bug 941428 - UITour.jsm not e10s friendly
+# [browser_UITour3.js] Bug 1113038
+# skip-if = os == "linux" || e10s # Linux: Bug 986760, Bug 989101; e10s: Bug 941428 - UITour.jsm not e10s friendly
 [browser_UITour_availableTargets.js]
 skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
 [browser_UITour_detach_tab.js]
 skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
 [browser_UITour_annotation_size_attributes.js]
 skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly.
 [browser_UITour_loop.js]
 skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly.
--- a/browser/components/uitour/test/browser_UITour2.js
+++ b/browser/components/uitour/test/browser_UITour2.js
@@ -62,38 +62,16 @@ let tests = [
               });
               gContentAPI.hideMenu("appMenu");
             }, "Info should move to the appMenu button");
           });
         }, "Info should be shown after showInfo() for fixed menu panel items");
       });
     }).then(null, Components.utils.reportError);
   },
-  taskify(function* test_pinnedTab() {
-    is(UITour.pinnedTabs.get(window), null, "Should not already have a pinned tab");
-
-    yield addPinnedTabPromise();
-
-    let tabInfo = UITour.pinnedTabs.get(window);
-    isnot(tabInfo, null, "Should have recorded data about a pinned tab after addPinnedTab()");
-    isnot(tabInfo.tab, null, "Should have added a pinned tab after addPinnedTab()");
-    is(tabInfo.tab.pinned, true, "Tab should be marked as pinned");
-
-    let tab = tabInfo.tab;
-
-    yield removePinnedTabPromise();
-    isnot(gBrowser.tabs[0], tab, "First tab should not be the pinned tab");
-    tabInfo = UITour.pinnedTabs.get(window);
-    is(tabInfo, null, "Should not have any data about the removed pinned tab after removePinnedTab()");
-
-    yield addPinnedTabPromise();
-    yield addPinnedTabPromise();
-    yield addPinnedTabPromise();
-    is(gBrowser.tabs[1].pinned, false, "After multiple calls of addPinnedTab, should still only have one pinned tab");
-  }),
   taskify(function* test_bookmarks_menu() {
     let bookmarksMenuButton = document.getElementById("bookmarks-menu-button");
 
     ise(bookmarksMenuButton.open, false, "Menu should initially be closed");
     gContentAPI.showMenu("bookmarks");
 
     yield waitForConditionPromise(() => {
       return bookmarksMenuButton.open;
--- a/browser/components/uitour/test/browser_UITour_availableTargets.js
+++ b/browser/components/uitour/test/browser_UITour_availableTargets.js
@@ -32,17 +32,16 @@ let tests = [
         "appMenu",
         "backForward",
         "bookmarks",
         "customize",
         "help",
         "home",
         "loop",
         "devtools",
-        "pinnedTab",
         "privateWindow",
         "quit",
         "search",
         "searchIcon",
         "urlbar",
         ...searchEngineTargets(),
         ...(hasWebIDE ? ["webide"] : [])
       ]);
@@ -63,17 +62,16 @@ let tests = [
         "addons",
         "appMenu",
         "backForward",
         "customize",
         "help",
         "loop",
         "devtools",
         "home",
-        "pinnedTab",
         "privateWindow",
         "quit",
         "search",
         "searchIcon",
         "urlbar",
         ...searchEngineTargets(),
         ...(hasWebIDE ? ["webide"] : [])
       ]);
@@ -99,17 +97,16 @@ let tests = [
         "appMenu",
         "backForward",
         "bookmarks",
         "customize",
         "help",
         "home",
         "loop",
         "devtools",
-        "pinnedTab",
         "privateWindow",
         "quit",
         "urlbar",
         ...(hasWebIDE ? ["webide"] : [])
       ]);
 
       CustomizableUI.reset();
       done();
--- a/browser/components/uitour/test/browser_UITour_detach_tab.js
+++ b/browser/components/uitour/test/browser_UITour_detach_tab.js
@@ -63,18 +63,18 @@ let tests = [
     gContentWindow = yield browserStartupDeferred.promise;
 
     // This highlight should be shown thanks to the visibilitychange listener.
     let newWindowHighlight = gContentWindow.document.getElementById("UITourHighlight");
     yield elementVisiblePromise(newWindowHighlight);
 
     let selectedTab = gContentWindow.gBrowser.selectedTab;
     is(selectedTab.linkedBrowser && selectedTab.linkedBrowser.contentDocument, gContentDoc, "Document should be selected in new window");
-    ok(UITour.originTabs && UITour.originTabs.has(gContentWindow), "Window should be known");
-    ok(UITour.originTabs.get(gContentWindow).has(selectedTab), "Tab should be known");
+    ok(UITour.tourBrowsersByWindow && UITour.tourBrowsersByWindow.has(gContentWindow), "Window should be known");
+    ok(UITour.tourBrowsersByWindow.get(gContentWindow).has(selectedTab.linkedBrowser), "Selected browser should be known");
 
     let shownPromise = promisePanelShown(gContentWindow);
     gContentAPI.showMenu("appMenu");
     yield shownPromise;
 
     isnot(gContentWindow.PanelUI.panel.state, "closed", "Panel should be open");
     ok(gContentWindow.PanelUI.contents.children.length > 0, "Panel contents should have children");
     gContentAPI.hideHighlight();
--- a/browser/components/uitour/test/browser_UITour_observe.js
+++ b/browser/components/uitour/test/browser_UITour_observe.js
@@ -43,9 +43,45 @@ let tests = [
       gContentAPI.observe(null);
       done();
     }
 
     gContentAPI.observe(listener, () => {
       UITour.notify("test-event-3", {key: "something"});
     });
   },
-];
\ No newline at end of file
+  function test_background_tab(done) {
+    function listener(event, params) {
+      is(event, "test-event-background-1", "Correct event name");
+      is(params, null, "No param object");
+      gContentAPI.observe(null);
+      gBrowser.removeCurrentTab();
+      done();
+    }
+
+    gContentAPI.observe(listener, () => {
+      gBrowser.selectedTab = gBrowser.addTab("about:blank");
+      isnot(gBrowser.selectedTab, gTestTab, "Make sure the selected tab changed");
+
+      UITour.notify("test-event-background-1");
+    });
+  },
+  // Make sure the tab isn't torn down when switching back to the tour one.
+  function test_background_then_foreground_tab(done) {
+    let blankTab = null;
+    function listener(event, params) {
+      is(event, "test-event-4", "Correct event name");
+      is(params, null, "No param object");
+      gContentAPI.observe(null);
+      gBrowser.removeTab(blankTab);
+      done();
+    }
+
+    gContentAPI.observe(listener, () => {
+      blankTab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
+      isnot(gBrowser.selectedTab, gTestTab, "Make sure the selected tab changed");
+      gBrowser.selectedTab = gTestTab;
+      is(gBrowser.selectedTab, gTestTab, "Switch back to the test tab");
+
+      UITour.notify("test-event-4");
+    });
+  },
+];
--- a/browser/components/uitour/test/head.js
+++ b/browser/components/uitour/test/head.js
@@ -140,35 +140,16 @@ function showMenuPromise(name) {
 }
 
 function waitForCallbackResultPromise() {
   return waitForConditionPromise(() => {
     return gContentWindow.callbackResult;
   }, "callback should be called");
 }
 
-function addPinnedTabPromise() {
-  gContentAPI.addPinnedTab();
-  return waitForConditionPromise(() => {
-    let tabInfo = UITour.pinnedTabs.get(window);
-    if (!tabInfo) {
-      return false;
-    }
-    return tabInfo.tab.pinned;
-  });
-}
-
-function removePinnedTabPromise() {
-  gContentAPI.removePinnedTab();
-  return waitForConditionPromise(() => {
-    let tabInfo = UITour.pinnedTabs.get(window);
-    return tabInfo == null;
-  });
-}
-
 function promisePanelShown(win) {
   let panelEl = win.PanelUI.panel;
   return promisePanelElementShown(win, panelEl);
 }
 
 function promisePanelElementEvent(win, aPanel, aEvent) {
   let deferred = Promise.defer();
   let timeoutId = win.setTimeout(() => {
@@ -246,18 +227,16 @@ function UITourTest() {
       let tooltip = document.getElementById("UITourTooltip");
       is_element_hidden(tooltip, "Tooltip should be closed/hidden after UITour tab is closed");
 
       ok(!PanelUI.panel.hasAttribute("noautohide"), "@noautohide on the menu panel should have been cleaned up");
       ok(!PanelUI.panel.hasAttribute("panelopen"), "The panel shouldn't have @panelopen");
       isnot(PanelUI.panel.state, "open", "The panel shouldn't be open");
       is(document.getElementById("PanelUI-menu-button").hasAttribute("open"), false, "Menu button should know that the menu is closed");
 
-      is(UITour.pinnedTabs.get(window), null, "Any pinned tab should be closed after UITour tab is closed");
-
       executeSoon(nextTest);
     });
   }
 
   function nextTest() {
     if (tests.length == 0) {
       finish();
       return;
--- a/browser/devtools/app-manager/app-validator.js
+++ b/browser/devtools/app-manager/app-validator.js
@@ -185,16 +185,20 @@ AppValidator.prototype._getOriginURL = f
     let manifestURL = Services.io.newURI(this.manifestURL, null, null);
     return Services.io.newURI(".", null, manifestURL).spec;
   } else if (this.project.type == "hosted") {
     return Services.io.newURI(this.project.location, null, null).prePath;
   }
 };
 
 AppValidator.prototype.validateLaunchPath = function (manifest) {
+  // Addons don't use index page (yet?)
+  if (manifest.role && manifest.role === "addon") {
+    return promise.resolve();
+  }
   let deferred = promise.defer();
   // The launch_path field has to start with a `/`
   if (manifest.launch_path && manifest.launch_path[0] !== "/") {
     this.error(strings.formatStringFromName("validator.nonAbsoluteLaunchPath", [manifest.launch_path], 1));
     deferred.resolve();
     return deferred.promise;
   }
   let origin = this._getOriginURL();
--- a/browser/devtools/debugger/test/browser_dbg_break-on-dom-event-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_break-on-dom-event-01.js
@@ -217,14 +217,13 @@ function triggerButtonClick() {
 
 function triggerInputChange() {
   gInput.focus();
   gInput.value = "foo";
   gInput.blur();
 }
 
 registerCleanupFunction(function() {
-  removeTab(gBrowser.selectedTab);
   gClient = null;
   gThreadClient = null;
   gInput = null;
   gButton = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_break-on-dom-event-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_break-on-dom-event-02.js
@@ -99,12 +99,11 @@ function triggerButtonClick(aNodeId) {
 
 function closeConnection() {
   let deferred = promise.defer();
   gClient.close(deferred.resolve);
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
-  removeTab(gBrowser.selectedTab);
   gClient = null;
   gThreadClient = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_chrome-debugging.js
+++ b/browser/devtools/debugger/test/browser_dbg_chrome-debugging.js
@@ -84,17 +84,16 @@ function onNewSource(aEvent, aPacket) {
 
 function resumeAndCloseConnection() {
   let deferred = promise.defer();
   gThreadClient.resume(() => gClient.close(deferred.resolve));
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
-  removeTab(gBrowser.selectedTab);
   gClient = null;
   gThreadClient = null;
   gAttached = null;
   gNewGlobal = null;
   gNewChromeSource = null;
 
   loader = null;
   DebuggerServer = null;
--- a/browser/devtools/debugger/test/browser_dbg_debugger-statement.js
+++ b/browser/devtools/debugger/test/browser_dbg_debugger-statement.js
@@ -80,12 +80,10 @@ function testDebuggerStatement([aGrip, a
 
 function closeConnection() {
   let deferred = promise.defer();
   gClient.close(deferred.resolve);
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
-  removeTab(gBrowser.selectedTab);
   gClient = null;
 });
-
--- a/browser/devtools/debugger/test/browser_dbg_event-listeners-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_event-listeners-01.js
@@ -142,11 +142,10 @@ function testEventListeners(aThreadClien
 
 function closeConnection() {
   let deferred = promise.defer();
   gClient.close(deferred.resolve);
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
-  removeTab(gBrowser.selectedTab);
   gClient = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_event-listeners-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_event-listeners-02.js
@@ -118,11 +118,10 @@ function testEventListeners(aThreadClien
 
 function closeConnection() {
   let deferred = promise.defer();
   gClient.close(deferred.resolve);
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
-  removeTab(gBrowser.selectedTab);
   gClient = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_event-listeners-03.js
+++ b/browser/devtools/debugger/test/browser_dbg_event-listeners-03.js
@@ -77,11 +77,10 @@ function testEventListeners(aThreadClien
 
 function closeConnection() {
   let deferred = promise.defer();
   gClient.close(deferred.resolve);
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
-  removeTab(gBrowser.selectedTab);
   gClient = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_on-pause-raise.js
+++ b/browser/devtools/debugger/test/browser_dbg_on-pause-raise.js
@@ -3,17 +3,17 @@
 
 /**
  * Tests that the toolbox is raised when the debugger gets paused.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
 let gTab, gPanel, gDebugger;
-let gNewTab, gFocusedWindow, gToolbox, gToolboxTab;
+let gFocusedWindow, gToolbox, gToolboxTab;
 
 function test() {
   initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gToolbox = gPanel._toolbox;
     gToolboxTab = gToolbox.doc.getElementById("toolbox-tab-jsdebugger");
@@ -24,17 +24,16 @@ function test() {
 
 function performTest() {
   addTab(TAB_URL).then(aTab => {
     isnot(aTab, gTab,
       "The newly added tab is different from the debugger's tab.");
     is(gBrowser.selectedTab, aTab,
       "Debugger's tab is not the selected tab.");
 
-    gNewTab = aTab;
     gFocusedWindow = window;
     testPause();
   });
 }
 
 function focusMainWindow() {
   // Make sure toolbox is not focused.
   window.addEventListener("focus", onFocus, true);
@@ -129,14 +128,12 @@ registerCleanupFunction(function() {
   // Revert to the default toolbox host, so that the following tests proceed
   // normally and not inside a non-default host.
   Services.prefs.setCharPref("devtools.toolbox.host", devtools.Toolbox.HostType.BOTTOM);
 
   gTab = null;
   gPanel = null;
   gDebugger = null;
 
-  removeTab(gNewTab);
-  gNewTab = null;
   gFocusedWindow = null;
   gToolbox = null;
   gToolboxTab = null;
 });
--- a/browser/devtools/debugger/test/head.js
+++ b/browser/devtools/debugger/test/head.js
@@ -33,20 +33,29 @@ const FRAME_SCRIPT_URL = getRootDirector
 gDevTools.testing = true;
 SimpleTest.registerCleanupFunction(() => {
   gDevTools.testing = false;
 });
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
-registerCleanupFunction(function() {
+registerCleanupFunction(function* () {
   info("finish() was called, cleaning up...");
   Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
 
+  while (gBrowser && gBrowser.tabs && gBrowser.tabs.length > 1) {
+    info("Destroying toolbox.");
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    yield gDevTools.closeToolbox(target);
+
+    info("Removing tab.");
+    gBrowser.removeCurrentTab();
+  }
+
   // Properly shut down the server to avoid memory leaks.
   DebuggerServer.destroy();
 
   // Debugger tests use a lot of memory, so force a GC to help fragmentation.
   info("Forcing GC after debugger test.");
   Cu.forceGC();
 });
 
--- a/browser/devtools/eyedropper/test/browser_eyedropper_cmd.js
+++ b/browser/devtools/eyedropper/test/browser_eyedropper_cmd.js
@@ -26,19 +26,20 @@ function spawnTest() {
 
   yield inspectAndWaitForCopy();
 
   yield helpers.closeToolbar(options);
   yield helpers.closeTab(options);
 }
 
 function inspectAndWaitForCopy() {
-  return waitForClipboard(() => {
-    inspectPage(); // setup: inspect the page
-  }, DIV_COLOR);
+  let copied = waitForClipboard(() => {}, DIV_COLOR);
+  let ready = inspectPage(); // resolves once eyedropper is destroyed
+  
+  return Promise.all([copied, ready]);
 }
 
 function inspectPage() {
   let target = document.documentElement;
   let win = window;
 
   // get location of the <div> in the content, offset from browser window
   let box = gBrowser.selectedBrowser.getBoundingClientRect();
@@ -49,11 +50,12 @@ function inspectPage() {
 
   return dropperStarted(dropper).then(() => {
     EventUtils.synthesizeMouse(target, x, y, { type: "mousemove" }, win);
 
     return dropperLoaded(dropper).then(() => {
       EventUtils.synthesizeMouse(target, x + 10, y + 10, { type: "mousemove" }, win);
 
       EventUtils.synthesizeMouse(target, x + 10, y + 10, {}, win);
+      return dropper.once("destroy");
     });
   })
 }
--- a/browser/devtools/netmonitor/netmonitor-controller.js
+++ b/browser/devtools/netmonitor/netmonitor-controller.js
@@ -396,16 +396,26 @@ let NetMonitorController = {
    */
   get supportsCustomRequest() {
     return this.webConsoleClient &&
            (this.webConsoleClient.traits.customNetworkRequest ||
             !this._target.isApp);
   },
 
   /**
+   * Getter that tells if the server includes the transferred (compressed /
+   * encoded) response size.
+   * @type boolean
+   */
+  get supportsTransferredResponseSize() {
+    return this.webConsoleClient &&
+           this.webConsoleClient.traits.transferredResponseSize;
+  },
+
+  /**
    * Getter that tells if the server can do network performance statistics.
    * @type boolean
    */
   get supportsPerfStats() {
     return this.tabClient &&
            (this.tabClient.traits.reconfigure || !this._target.isApp);
   },
 
@@ -601,16 +611,17 @@ NetworkEventsHandler.prototype = {
           statusText: aPacket.response.statusText,
           headersSize: aPacket.response.headersSize
         });
         window.emit(EVENTS.STARTED_RECEIVING_RESPONSE, actor);
         break;
       case "responseContent":
         NetMonitorView.RequestsMenu.updateRequest(aPacket.from, {
           contentSize: aPacket.contentSize,
+          transferredSize: aPacket.transferredSize,
           mimeType: aPacket.mimeType
         });
         this.webConsoleClient.getResponseContent(actor, this._onResponseContent);
         window.emit(EVENTS.UPDATING_RESPONSE_CONTENT, actor);
         break;
       case "eventTimings":
         NetMonitorView.RequestsMenu.updateRequest(aPacket.from, {
           totalTime: aPacket.totalTime
--- a/browser/devtools/netmonitor/netmonitor-view.js
+++ b/browser/devtools/netmonitor/netmonitor-view.js
@@ -412,16 +412,21 @@ RequestsMenuView.prototype = Heritage.ex
       $("#requests-menu-network-summary-label").addEventListener("click", this._onContextPerfCommand, false);
       $("#network-statistics-back-button").addEventListener("command", this._onContextPerfCommand, false);
     } else {
       $("#notice-perf-message").hidden = true;
       $("#request-menu-context-perf").hidden = true;
       $("#requests-menu-network-summary-button").hidden = true;
       $("#requests-menu-network-summary-label").hidden = true;
     }
+
+    if (!NetMonitorController.supportsTransferredResponseSize) {
+      $("#requests-menu-transferred-header-box").hidden = true;
+      $("#requests-menu-item-template .requests-menu-transferred").hidden = true;
+    }
   },
 
   /**
    * Destruction function, called when the network monitor is closed.
    */
   destroy: function() {
     dumpn("Destroying the SourcesView");
 
@@ -795,18 +800,18 @@ RequestsMenuView.prototype = Heritage.ex
     flash: this.isFlash,
     other: this.isOther
   }),
 
   /**
    * Sorts all network requests in this container by a specified detail.
    *
    * @param string aType
-   *        Either "status", "method", "file", "domain", "type", "size" or
-   *        "waterfall".
+   *        Either "status", "method", "file", "domain", "type", "transferred",
+   *        "size" or "waterfall".
    */
   sortBy: function(aType = "waterfall") {
     let target = $("#requests-menu-" + aType + "-button");
     let headers = document.querySelectorAll(".requests-menu-header-button");
 
     for (let header of headers) {
       if (header != target) {
         header.removeAttribute("sorted");
@@ -857,16 +862,23 @@ RequestsMenuView.prototype = Heritage.ex
         break;
       case "type":
         if (direction == "ascending") {
           this.sortContents(this._byType);
         } else {
           this.sortContents((a, b) => !this._byType(a, b));
         }
         break;
+      case "transferred":
+        if (direction == "ascending") {
+          this.sortContents(this._byTransferred);
+        } else {
+          this.sortContents((a, b) => !this._byTransferred(a, b));
+        }
+        break;
       case "size":
         if (direction == "ascending") {
           this.sortContents(this._bySize);
         } else {
           this.sortContents((a, b) => !this._bySize(a, b));
         }
         break;
       case "waterfall":
@@ -989,18 +1001,23 @@ RequestsMenuView.prototype = Heritage.ex
   _byType: function({ attachment: first }, { attachment: second }) {
     let firstType = this._getAbbreviatedMimeType(first.mimeType).toLowerCase();
     let secondType = this._getAbbreviatedMimeType(second.mimeType).toLowerCase();
     return firstType == secondType
       ? first.startedMillis > second.startedMillis
       : firstType > secondType;
   },
 
-  _bySize: function({ attachment: first }, { attachment: second })
-    first.contentSize > second.contentSize,
+  _byTransferred: function({ attachment: first }, { attachment: second }) {
+    return first.transferredSize > second.transferredSize;
+  },
+
+  _bySize: function({ attachment: first }, { attachment: second }) {
+    return first.contentSize > second.contentSize;
+  },
 
   /**
    * Refreshes the status displayed in this container's footer, providing
    * concise information about all requests.
    */
   refreshSummary: function() {
     let visibleItems = this.visibleItems;
     let visibleRequestsCount = visibleItems.length;
@@ -1173,16 +1190,20 @@ RequestsMenuView.prototype = Heritage.ex
             break;
           case "headersSize":
             requestItem.attachment.headersSize = value;
             break;
           case "contentSize":
             requestItem.attachment.contentSize = value;
             this.updateMenuView(requestItem, key, value);
             break;
+          case "transferredSize":
+            requestItem.attachment.transferredSize = value;
+            this.updateMenuView(requestItem, key, value);
+            break;
           case "mimeType":
             requestItem.attachment.mimeType = value;
             this.updateMenuView(requestItem, key, value);
             break;
           case "responseContent":
             // If there's no mime type available when the response content
             // is received, assume text/plain as a fallback.
             if (!requestItem.attachment.mimeType) {
@@ -1330,16 +1351,30 @@ RequestsMenuView.prototype = Heritage.ex
         let kb = aValue / 1024;
         let size = L10N.numberWithDecimals(kb, CONTENT_SIZE_DECIMALS);
         let node = $(".requests-menu-size", target);
         let text = L10N.getFormatStr("networkMenu.sizeKB", size);
         node.setAttribute("value", text);
         node.setAttribute("tooltiptext", text);
         break;
       }
+      case "transferredSize": {
+        let text;
+        if (aValue === null) {
+          text = L10N.getStr("networkMenu.sizeUnavailable");
+        } else {
+          let kb = aValue / 1024;
+          let size = L10N.numberWithDecimals(kb, CONTENT_SIZE_DECIMALS);
+          text = L10N.getFormatStr("networkMenu.sizeKB", size);
+        }
+        let node = $(".requests-menu-transferred", target);
+        node.setAttribute("value", text);
+        node.setAttribute("tooltiptext", text);
+        break;
+      }
       case "mimeType": {
         let type = this._getAbbreviatedMimeType(aValue);
         let node = $(".requests-menu-type", target);
         let text = CONTENT_MIME_TYPE_ABBREVIATIONS[type] || type;
         node.setAttribute("value", text);
         node.setAttribute("tooltiptext", aValue);
         break;
       }
--- a/browser/devtools/netmonitor/netmonitor.xul
+++ b/browser/devtools/netmonitor/netmonitor.xul
@@ -98,16 +98,26 @@
                     align="center">
                 <button id="requests-menu-type-button"
                         class="requests-menu-header-button requests-menu-type"
                         data-key="type"
                         label="&netmonitorUI.toolbar.type;"
                         flex="1">
                 </button>
               </hbox>
+              <hbox id="requests-menu-transferred-header-box"
+                    class="requests-menu-header requests-menu-transferred"
+                    align="center">
+                <button id="requests-menu-transferred-button"
+                        class="requests-menu-header-button requests-menu-transferred"
+                        data-key="transferred"
+                        label="&netmonitorUI.toolbar.transferred;"
+                        flex="1">
+                </button>
+              </hbox>
               <hbox id="requests-menu-size-header-box"
                     class="requests-menu-header requests-menu-size"
                     align="center">
                 <button id="requests-menu-size-button"
                         class="requests-menu-header-button requests-menu-size"
                         data-key="size"
                         label="&netmonitorUI.toolbar.size;"
                         flex="1">
@@ -176,16 +186,18 @@
                     align="center">
                 <image class="requests-security-state-icon" />
                 <label class="plain requests-menu-domain"
                        crop="end"
                        flex="1"/>
               </hbox>
               <label class="plain requests-menu-subitem requests-menu-type"
                      crop="end"/>
+              <label class="plain requests-menu-subitem requests-menu-transferred"
+                     crop="end"/>
               <label class="plain requests-menu-subitem requests-menu-size"
                      crop="end"/>
               <hbox class="requests-menu-subitem requests-menu-waterfall"
                     align="center"
                     flex="1">
                 <hbox class="requests-menu-timings"
                       align="center">
                   <label class="plain requests-menu-timings-total"/>
--- a/browser/devtools/netmonitor/test/browser_net_simple-request-data.js
+++ b/browser/devtools/netmonitor/test/browser_net_simple-request-data.js
@@ -60,16 +60,18 @@ function test() {
         "The httpVersion should not yet be set.");
       is(requestItem.attachment.status, undefined,
         "The status should not yet be set.");
       is(requestItem.attachment.statusText, undefined,
         "The statusText should not yet be set.");
 
       is(requestItem.attachment.headersSize, undefined,
         "The headersSize should not yet be set.");
+      is(requestItem.attachment.transferredSize, undefined,
+        "The transferredSize should not yet be set.");
       is(requestItem.attachment.contentSize, undefined,
         "The contentSize should not yet be set.");
 
       is(requestItem.attachment.mimeType, undefined,
         "The mimeType should not yet be set.");
       is(requestItem.attachment.responseContent, undefined,
         "The responseContent should not yet be set.");
 
@@ -151,24 +153,27 @@ function test() {
         status: "200",
         statusText: "Och Aye"
       });
     });
 
     aMonitor.panelWin.once(aMonitor.panelWin.EVENTS.UPDATING_RESPONSE_CONTENT, () => {
       let requestItem = RequestsMenu.getItemAtIndex(0);
 
+      is(requestItem.attachment.transferredSize, "12",
+        "The transferredSize attachment has an incorrect value.");
       is(requestItem.attachment.contentSize, "12",
         "The contentSize attachment has an incorrect value.");
       is(requestItem.attachment.mimeType, "text/plain; charset=utf-8",
         "The mimeType attachment has an incorrect value.");
 
       verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
         type: "plain",
         fullMimeType: "text/plain; charset=utf-8",
+        transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
         size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
       });
     });
 
     aMonitor.panelWin.once(aMonitor.panelWin.EVENTS.RECEIVED_RESPONSE_CONTENT, () => {
       let requestItem = RequestsMenu.getItemAtIndex(0);
 
       ok(requestItem.attachment.responseContent,
@@ -178,16 +183,17 @@ function test() {
       is(requestItem.attachment.responseContent.content.text, "Hello world!",
         "The responseContent attachment has an incorrect |content.text| property.");
       is(requestItem.attachment.responseContent.content.size, 12,
         "The responseContent attachment has an incorrect |content.size| property.");
 
       verifyRequestItemTarget(requestItem, "GET", SIMPLE_SJS, {
         type: "plain",
         fullMimeType: "text/plain; charset=utf-8",
+        transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
         size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
       });
     });
 
     aMonitor.panelWin.once(aMonitor.panelWin.EVENTS.UPDATING_EVENT_TIMINGS, () => {
       let requestItem = RequestsMenu.getItemAtIndex(0);
 
       is(typeof requestItem.attachment.totalTime, "number",
--- a/browser/devtools/netmonitor/test/browser_net_sort-01.js
+++ b/browser/devtools/netmonitor/test/browser_net_sort-01.js
@@ -197,52 +197,57 @@ function test() {
         "The requests menu items aren't ordered correctly. Fifth item is misplaced.");
 
       verifyRequestItemTarget(RequestsMenu.getItemAtIndex(a),
         "GET", STATUS_CODES_SJS + "?sts=100", {
           status: 101,
           statusText: "Switching Protocols",
           type: "plain",
           fullMimeType: "text/plain; charset=utf-8",
+          transferred: L10N.getStr("networkMenu.sizeUnavailable"),
           size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0),
           time: true
         });
       verifyRequestItemTarget(RequestsMenu.getItemAtIndex(b),
         "GET", STATUS_CODES_SJS + "?sts=200", {
           status: 202,
           statusText: "Created",
           type: "plain",
           fullMimeType: "text/plain; charset=utf-8",
+          transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
           size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
           time: true
         });
       verifyRequestItemTarget(RequestsMenu.getItemAtIndex(c),
         "GET", STATUS_CODES_SJS + "?sts=300", {
           status: 303,
           statusText: "See Other",
           type: "plain",
           fullMimeType: "text/plain; charset=utf-8",
+          transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
           size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0),
           time: true
         });
       verifyRequestItemTarget(RequestsMenu.getItemAtIndex(d),
         "GET", STATUS_CODES_SJS + "?sts=400", {
           status: 404,
           statusText: "Not Found",
           type: "plain",
           fullMimeType: "text/plain; charset=utf-8",
+          transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
           size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
           time: true
         });
       verifyRequestItemTarget(RequestsMenu.getItemAtIndex(e),
         "GET", STATUS_CODES_SJS + "?sts=500", {
           status: 501,
           statusText: "Not Implemented",
           type: "plain",
           fullMimeType: "text/plain; charset=utf-8",
+          transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
           size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
           time: true
         });
 
       return promise.resolve(null);
     }
 
     aDebuggee.performRequests();
--- a/browser/devtools/netmonitor/test/browser_net_sort-02.js
+++ b/browser/devtools/netmonitor/test/browser_net_sort-02.js
@@ -98,16 +98,34 @@ function test() {
         })
         .then(() => {
           info("Testing type sort, ascending. Checking sort loops correctly.");
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-type-button"));
           testHeaders("type", "ascending");
           return testContents([0, 1, 2, 3, 4]);
         })
         .then(() => {
+          info("Testing transferred sort, ascending.");
+          EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-transferred-button"));
+          testHeaders("transferred", "ascending");
+          return testContents([0, 1, 2, 3, 4]);
+        })
+        .then(() => {
+          info("Testing transferred sort, descending.");
+          EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-transferred-button"));
+          testHeaders("transferred", "descending");
+          return testContents([4, 3, 2, 1, 0]);
+        })
+        .then(() => {
+          info("Testing transferred sort, ascending. Checking sort loops correctly.");
+          EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-transferred-button"));
+          testHeaders("transferred", "ascending");
+          return testContents([0, 1, 2, 3, 4]);
+        })
+        .then(() => {
           info("Testing size sort, ascending.");
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
           testHeaders("size", "ascending");
           return testContents([0, 1, 2, 3, 4]);
         })
         .then(() => {
           info("Testing size sort, descending.");
           EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
@@ -194,56 +212,61 @@ function test() {
 
       verifyRequestItemTarget(RequestsMenu.getItemAtIndex(a),
         "GET1", SORTING_SJS + "?index=1", {
           fuzzyUrl: true,
           status: 101,
           statusText: "Meh",
           type: "1",
           fullMimeType: "text/1",
+          transferred: L10N.getStr("networkMenu.sizeUnavailable"),
           size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0),
           time: true
         });
       verifyRequestItemTarget(RequestsMenu.getItemAtIndex(b),
         "GET2", SORTING_SJS + "?index=2", {
           fuzzyUrl: true,
           status: 200,
           statusText: "Meh",
           type: "2",
           fullMimeType: "text/2",
+          transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
           size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
           time: true
         });
       verifyRequestItemTarget(RequestsMenu.getItemAtIndex(c),
         "GET3", SORTING_SJS + "?index=3", {
           fuzzyUrl: true,
           status: 300,
           statusText: "Meh",
           type: "3",
           fullMimeType: "text/3",
+          transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
           size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
           time: true
         });
       verifyRequestItemTarget(RequestsMenu.getItemAtIndex(d),
         "GET4", SORTING_SJS + "?index=4", {
           fuzzyUrl: true,
           status: 400,
           statusText: "Meh",
           type: "4",
           fullMimeType: "text/4",
+          transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.03),
           size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.03),
           time: true
         });
       verifyRequestItemTarget(RequestsMenu.getItemAtIndex(e),
         "GET5", SORTING_SJS + "?index=5", {
           fuzzyUrl: true,
           status: 500,
           statusText: "Meh",
           type: "5",
           fullMimeType: "text/5",
+          transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
           size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
           time: true
         });
 
       return promise.resolve(null);
     }
 
     aDebuggee.performRequests();
--- a/browser/devtools/netmonitor/test/browser_net_sort-03.js
+++ b/browser/devtools/netmonitor/test/browser_net_sort-03.js
@@ -125,64 +125,69 @@ function test() {
       for (let i = 0, len = aOrder.length / 5; i < len; i++) {
         verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i]),
           "GET1", SORTING_SJS + "?index=1", {
             fuzzyUrl: true,
             status: 101,
             statusText: "Meh",
             type: "1",
             fullMimeType: "text/1",
+            transferred: L10N.getStr("networkMenu.sizeUnavailable"),
             size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0),
             time: true
           });
       }
       for (let i = 0, len = aOrder.length / 5; i < len; i++) {
         verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len]),
           "GET2", SORTING_SJS + "?index=2", {
             fuzzyUrl: true,
             status: 200,
             statusText: "Meh",
             type: "2",
             fullMimeType: "text/2",
+            transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
             size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.01),
             time: true
           });
       }
       for (let i = 0, len = aOrder.length / 5; i < len; i++) {
         verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len * 2]),
           "GET3", SORTING_SJS + "?index=3", {
             fuzzyUrl: true,
             status: 300,
             statusText: "Meh",
             type: "3",
             fullMimeType: "text/3",
+            transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
             size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.02),
             time: true
           });
       }
       for (let i = 0, len = aOrder.length / 5; i < len; i++) {
         verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len * 3]),
           "GET4", SORTING_SJS + "?index=4", {
             fuzzyUrl: true,
             status: 400,
             statusText: "Meh",
             type: "4",
             fullMimeType: "text/4",
+            transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.03),
             size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.03),
             time: true
           });
       }
       for (let i = 0, len = aOrder.length / 5; i < len; i++) {
         verifyRequestItemTarget(RequestsMenu.getItemAtIndex(aOrder[i + len * 4]),
           "GET5", SORTING_SJS + "?index=5", {
             fuzzyUrl: true,
             status: 500,
             statusText: "Meh",
             type: "5",
             fullMimeType: "text/5",
+            transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
             size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 0.04),
             time: true
           });
       }
 
       return promise.resolve(null);
     }
 
--- a/browser/devtools/netmonitor/test/browser_net_timeline_ticks.js
+++ b/browser/devtools/netmonitor/test/browser_net_timeline_ticks.js
@@ -7,16 +7,22 @@
 
 function test() {
   initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
     info("Starting test... ");
 
     let { document, L10N, NetMonitorView } = aMonitor.panelWin;
     let { RequestsMenu } = NetMonitorView;
 
+    // Disable transferred size column support for this test.
+    // Without this, the waterfall only has enough room for one division, which
+    // would remove most of the value of this test.
+    document.querySelector("#requests-menu-transferred-header-box").hidden = true;
+    document.querySelector("#requests-menu-item-template .requests-menu-transferred").hidden = true;
+
     RequestsMenu.lazyUpdate = false;
 
     ok(document.querySelector("#requests-menu-waterfall-label"),
       "An timeline label should be displayed when the frontend is opened.");
     ok(document.querySelectorAll(".requests-menu-timings-division").length == 0,
       "No tick labels should be displayed when the frontend is opened.");
 
     ok(!RequestsMenu._canvas,
--- a/browser/devtools/netmonitor/test/head.js
+++ b/browser/devtools/netmonitor/test/head.js
@@ -261,17 +261,17 @@ function verifyRequestItemTarget(aReques
 
   let requestsMenu = aRequestItem.ownerView;
   let widgetIndex = requestsMenu.indexOfItem(aRequestItem);
   let visibleIndex = requestsMenu.visibleItems.indexOf(aRequestItem);
 
   info("Widget index of item: " + widgetIndex);
   info("Visible index of item: " + visibleIndex);
 
-  let { fuzzyUrl, status, statusText, type, fullMimeType, size, time } = aData;
+  let { fuzzyUrl, status, statusText, type, fullMimeType, transferred, size, time } = aData;
   let { attachment, target } = aRequestItem
 
   let uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
   let name = uri.fileName || "/";
   let query = uri.query;
   let hostPort = uri.hostPort;
 
   if (fuzzyUrl) {
@@ -316,16 +316,24 @@ function verifyRequestItemTarget(aReques
   if (type !== undefined) {
     let value = target.querySelector(".requests-menu-type").getAttribute("value");
     let tooltip = target.querySelector(".requests-menu-type").getAttribute("tooltiptext");
     info("Displayed type: " + value);
     info("Tooltip type: " + tooltip);
     is(value, type, "The displayed type is incorrect.");
     is(tooltip, fullMimeType, "The tooltip type is incorrect.");
   }
+  if (transferred !== undefined) {
+    let value = target.querySelector(".requests-menu-transferred").getAttribute("value");
+    let tooltip = target.querySelector(".requests-menu-transferred").getAttribute("tooltiptext");
+    info("Displayed transferred size: " + value);
+    info("Tooltip transferred size: " + tooltip);
+    is(value, transferred, "The displayed transferred size is incorrect.");
+    is(tooltip, transferred, "The tooltip transferred size is incorrect.");
+  }
   if (size !== undefined) {
     let value = target.querySelector(".requests-menu-size").getAttribute("value");
     let tooltip = target.querySelector(".requests-menu-size").getAttribute("tooltiptext");
     info("Displayed size: " + value);
     info("Tooltip size: " + tooltip);
     is(value, size, "The displayed size is incorrect.");
     is(tooltip, size, "The tooltip size is incorrect.");
   }
--- a/browser/devtools/styleinspector/rule-view.js
+++ b/browser/devtools/styleinspector/rule-view.js
@@ -119,16 +119,17 @@ function createDummyDocument() {
  *
  * @constructor
  */
 function ElementStyle(aElement, aStore, aPageStyle, aShowUserAgentStyles) {
   this.element = aElement;
   this.store = aStore || {};
   this.pageStyle = aPageStyle;
   this.showUserAgentStyles = aShowUserAgentStyles;
+  this.rules = [];
 
   // We don't want to overwrite this.store.userProperties so we only create it
   // if it doesn't already exist.
   if (!("userProperties" in this.store)) {
     this.store.userProperties = new UserProperties();
   }
 
   if (!("disabled" in this.store)) {
--- a/browser/devtools/styleinspector/style-inspector.js
+++ b/browser/devtools/styleinspector/style-inspector.js
@@ -46,26 +46,32 @@ function RuleViewTool(inspector, window,
   this.inspector.sidebar.on("ruleview-selected", this.onPanelSelected);
 
   this.onSelected();
 }
 
 
 RuleViewTool.prototype = {
   isSidebarActive: function() {
+    if (!this.view) {
+      return false;
+    }
     return this.inspector.sidebar.getCurrentTabID() == "ruleview";
   },
 
   onSelected: function(event) {
     // Ignore the event if the view has been destroyed, or if it's inactive.
     // But only if the current selection isn't null. If it's been set to null,
     // let the update go through as this is needed to empty the view on navigation.
-    let isDestroyed = !this.view;
+    if (!this.view) {
+      return;
+    }
+
     let isInactive = !this.isSidebarActive() && this.inspector.selection.nodeFront;
-    if (isDestroyed || isInactive) {
+    if (isInactive) {
       return;
     }
 
     this.view.setPageStyle(this.inspector.pageStyle);
 
     if (!this.inspector.selection.isConnected() ||
         !this.inspector.selection.isElementNode()) {
       this.view.selectElement(null);
@@ -173,26 +179,32 @@ function ComputedViewTool(inspector, win
 
   this.view.selectElement(null);
 
   this.onSelected();
 }
 
 ComputedViewTool.prototype = {
   isSidebarActive: function() {
+    if (!this.view) {
+      return;
+    }
     return this.inspector.sidebar.getCurrentTabID() == "computedview";
   },
 
   onSelected: function(event) {
     // Ignore the event if the view has been destroyed, or if it's inactive.
     // But only if the current selection isn't null. If it's been set to null,
     // let the update go through as this is needed to empty the view on navigation.
-    let isDestroyed = !this.view;
+    if (!this.view) {
+      return;
+    }
+
     let isInactive = !this.isSidebarActive() && this.inspector.selection.nodeFront;
-    if (isDestroyed || isInactive) {
+    if (isInactive) {
       return;
     }
 
     this.view.setPageStyle(this.inspector.pageStyle);
 
     if (!this.inspector.selection.isConnected() ||
         !this.inspector.selection.isElementNode()) {
       this.view.selectElement(null);
--- a/browser/devtools/webaudioeditor/webaudioeditor.xul
+++ b/browser/devtools/webaudioeditor/webaudioeditor.xul
@@ -90,17 +90,17 @@
                 <hbox class="devtools-toolbarbutton-group">
                   <toolbarbutton class="bypass devtools-toolbarbutton"
                                  data-command="bypass"
                                  tabindex="0"/>
                 </hbox>
               </toolbar>
               <tabs>
                 <tab id="properties-tab"
-                     label="&webAudioEditorUI.tab.properties;"/>
+                     label="&webAudioEditorUI.tab.properties2;"/>
                 <tab id="automation-tab"
                      label="&webAudioEditorUI.tab.automation;"/>
               </tabs>
               <tabpanels flex="1">
                 <!-- Properties Panel -->
                 <tabpanel id="properties-tabpanel"
                           class="tabpanel-content">
                   <vbox id="properties-content" flex="1" hidden="true">
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -251,16 +251,17 @@ skip-if = e10s # Bug 1042253 - webconsol
 [browser_webconsole_bug_622303_persistent_filters.js]
 [browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js]
 run-if = os == "win"
 [browser_webconsole_bug_630733_response_redirect_headers.js]
 [browser_webconsole_bug_632275_getters_document_width.js]
 [browser_webconsole_bug_632347_iterators_generators.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_632817.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_642108_pruneTest.js]
 [browser_webconsole_autocomplete_and_selfxss.js]
 [browser_webconsole_bug_644419_log_limits.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException)
 [browser_webconsole_bug_646025_console_file_location.js]
 [browser_webconsole_bug_651501_document_body_autocomplete.js]
 [browser_webconsole_bug_653531_highlighter_console_helper.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
--- a/browser/devtools/webconsole/test/browser_console.js
+++ b/browser/devtools/webconsole/test/browser_console.js
@@ -75,17 +75,17 @@ function consoleOpened(hud)
         text: "foobarExceptionBug587757",
         category: CATEGORY_JS,
         severity: SEVERITY_ERROR,
       },
       {
         name: "network message",
         text: "test-console.html",
         category: CATEGORY_NETWORK,
-        severity: SEVERITY_LOG,
+        severity: SEVERITY_INFO,
       },
     ],
   });
 }
 
 function waitForConsole() {
   let deferred = promise.defer();
 
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_622303_persistent_filters.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_622303_persistent_filters.js
@@ -1,16 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const prefs = {
   "net": [
     "network",
     "netwarn",
-    "networkinfo",
+    "netxhr",
+    "networkinfo"
   ],
   "css": [
     "csserror",
     "cssparser",
     "csslog"
   ],
   "js": [
     "exception",
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_632817.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_632817.js
@@ -16,20 +16,23 @@ const TEST_URI = "data:text/html;charset
 let lastRequest = null;
 let requestCallback = null;
 let hud, browser;
 
 function test()
 {
   const PREF = "devtools.webconsole.persistlog";
   let original = Services.prefs.getBoolPref("devtools.webconsole.filter.networkinfo");
+  let originalXhr = Services.prefs.getBoolPref("devtools.webconsole.filter.netxhr");
   Services.prefs.setBoolPref("devtools.webconsole.filter.networkinfo", true);
+  Services.prefs.setBoolPref("devtools.webconsole.filter.netxhr", true);
   Services.prefs.setBoolPref(PREF, true);
   registerCleanupFunction(() => {
     Services.prefs.setBoolPref("devtools.webconsole.filter.networkinfo", original);
+    Services.prefs.setBoolPref("devtools.webconsole.filter.netxhr", originalXhr);
     Services.prefs.clearUserPref(PREF);
   });
 
   loadTab(TEST_URI).then((tab) => {
     browser = tab.browser;
     openConsole().then((aHud) => {
       hud = aHud;
 
@@ -134,17 +137,17 @@ function testFormSubmission()
           text: "test-network-request.html",
           category: CATEGORY_NETWORK,
           severity: SEVERITY_LOG,
           count: 3,
         },
         {
           text: "test-data.json",
           category: CATEGORY_NETWORK,
-          severity: SEVERITY_LOG,
+          severity: SEVERITY_INFO,
           count: 2,
         },
       ],
     }).then(testLiveFilteringOnSearchStrings);
   };
 
   let form = content.document.querySelector("form");
   ok(form, "we have the HTML form");
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -100,24 +100,24 @@ const SEVERITY_CLASS_FRAGMENTS = [
 ];
 
 // The preference keys to use for each category/severity combination, indexed
 // first by category (rows) and then by severity (columns).
 //
 // Most of these rather idiosyncratic names are historical and predate the
 // division of message type into "category" and "severity".
 const MESSAGE_PREFERENCE_KEYS = [
-//  Error         Warning       Info      Log
-  [ "network",    "netwarn",    null,     "networkinfo", ],  // Network
-  [ "csserror",   "cssparser",  null,     "csslog",      ],  // CSS
-  [ "exception",  "jswarn",     null,     "jslog",       ],  // JS
-  [ "error",      "warn",       "info",   "log",         ],  // Web Developer
-  [ null,         null,         null,     null,          ],  // Input
-  [ null,         null,         null,     null,          ],  // Output
-  [ "secerror",   "secwarn",    null,     null,          ],  // Security
+//  Error         Warning       Info       Log
+  [ "network",    "netwarn",    "netxhr",  "networkinfo", ],  // Network
+  [ "csserror",   "cssparser",  null,      "csslog",      ],  // CSS
+  [ "exception",  "jswarn",     null,      "jslog",       ],  // JS
+  [ "error",      "warn",       "info",    "log",         ],  // Web Developer
+  [ null,         null,         null,      null,          ],  // Input
+  [ null,         null,         null,      null,          ],  // Output
+  [ "secerror",   "secwarn",    null,      null,          ],  // Security
 ];
 
 // A mapping from the console API log event levels to the Web Console
 // severities.
 const LEVELS = {
   error: SEVERITY_ERROR,
   exception: SEVERITY_ERROR,
   assert: SEVERITY_ERROR,
@@ -542,35 +542,39 @@ WebConsoleFrame.prototype = {
     let reverseSaveBodiesPref = ({ target: aElement }) => {
       this.getSaveRequestAndResponseBodies().then(aValue => {
         this.setSaveRequestAndResponseBodies(!aValue);
         aElement.setAttribute("checked", aValue);
         this.emit("save-bodies-pref-reversed");
       });
     }
 
+    let saveBodiesDisabled = !this.getFilterState("networkinfo") &&
+                             !this.getFilterState("netxhr") &&
+                             !this.getFilterState("network");
+
     let saveBodies = doc.getElementById("saveBodies");
     saveBodies.addEventListener("command", reverseSaveBodiesPref);
-    saveBodies.disabled = !this.getFilterState("networkinfo") &&
-                          !this.getFilterState("network");
+    saveBodies.disabled = saveBodiesDisabled;
 
     let saveBodiesContextMenu = doc.getElementById("saveBodiesContextMenu");
     saveBodiesContextMenu.addEventListener("command", reverseSaveBodiesPref);
-    saveBodiesContextMenu.disabled = !this.getFilterState("networkinfo") &&
-                                     !this.getFilterState("network");
+    saveBodiesContextMenu.disabled = saveBodiesDisabled;
 
     saveBodies.parentNode.addEventListener("popupshowing", () => {
       updateSaveBodiesPrefUI(saveBodies);
       saveBodies.disabled = !this.getFilterState("networkinfo") &&
+                            !this.getFilterState("netxhr") &&
                             !this.getFilterState("network");
     });
 
     saveBodiesContextMenu.parentNode.addEventListener("popupshowing", () => {
       updateSaveBodiesPrefUI(saveBodiesContextMenu);
       saveBodiesContextMenu.disabled = !this.getFilterState("networkinfo") &&
+                                       !this.getFilterState("netxhr") &&
                                        !this.getFilterState("network");
     });
 
     let clearButton = doc.getElementsByClassName("webconsole-clear-console-button")[0];
     clearButton.addEventListener("command", () => {
       this.owner._onClearButton();
       this.jsterm.clearOutput(true);
     });
@@ -619,17 +623,17 @@ WebConsoleFrame.prototype = {
   /**
    * Initialize the default filter preferences.
    * @private
    */
   _initDefaultFilterPrefs: function WCF__initDefaultFilterPrefs()
   {
     let prefs = ["network", "networkinfo", "csserror", "cssparser", "csslog",
                  "exception", "jswarn", "jslog", "error", "info", "warn", "log",
-                 "secerror", "secwarn", "netwarn"];
+                 "secerror", "secwarn", "netwarn", "netxhr"];
     for (let pref of prefs) {
       this.filterPrefs[pref] = Services.prefs
                                .getBoolPref(this._filterPrefsPrefix + pref);
     }
   },
 
   /**
    * Attach / detach reflow listeners depending on the checked status
@@ -878,18 +882,19 @@ WebConsoleFrame.prototype = {
       case "menuitem": {
         let state = target.getAttribute("checked") !== "true";
         target.setAttribute("checked", state);
 
         let prefKey = target.getAttribute("prefKey");
         this.setFilterState(prefKey, state);
 
         // Disable the log response and request body if network logging is off.
-        if (prefKey == "networkinfo" || prefKey == "network") {
+        if (prefKey == "networkinfo" || prefKey == "netxhr" || prefKey == "network") {
           let checkState = !this.getFilterState("networkinfo") &&
+                           !this.getFilterState("netxhr") &&
                            !this.getFilterState("network");
           this.document.getElementById("saveBodies").disabled = checkState;
           this.document.getElementById("saveBodiesContextMenu").disabled = checkState;
         }
 
         // Adjust the state of the button appropriately.
         let menuPopup = target.parentNode;
 
@@ -1488,16 +1493,19 @@ WebConsoleFrame.prototype = {
     let networkInfo = this._networkRequests[actorId];
     if (!networkInfo) {
       return null;
     }
 
     let request = networkInfo.request;
     let clipboardText = request.method + " " + request.url;
     let severity = SEVERITY_LOG;
+    if (networkInfo.isXHR) {
+      severity = SEVERITY_INFO;
+    }
     let mixedRequest =
       WebConsoleUtils.isMixedHTTPSRequest(request.url, this.contentLocation);
     if (mixedRequest) {
       severity = SEVERITY_WARNING;
     }
 
     let methodNode = this.document.createElementNS(XHTML_NS, "span");
     methodNode.className = "method";
@@ -1745,16 +1753,17 @@ WebConsoleFrame.prototype = {
       actor: aActor.actor,
       discardRequestBody: true,
       discardResponseBody: true,
       startedDateTime: aActor.startedDateTime,
       request: {
         url: aActor.url,
         method: aActor.method,
       },
+      isXHR: aActor.isXHR,
       response: {},
       timings: {},
       updates: [], // track the list of network event updates
       private: aActor.private,
     };
 
     this._networkRequests[aActor.actor] = networkInfo;
     this.outputMessage(CATEGORY_NETWORK, this.logNetEvent, [aActor]);
--- a/browser/devtools/webconsole/webconsole.xul
+++ b/browser/devtools/webconsole/webconsole.xul
@@ -93,16 +93,18 @@ function goUpdateConsoleCommands() {
                          accesskeyMacOSX="&btnPageNet.accesskeyMacOSX;"
                          accesskey="&btnPageNet.accesskey;"
                          tabindex="3">
             <menupopup id="net-contextmenu">
               <menuitem label="&btnConsoleErrors;" type="checkbox" autocheck="false"
                         prefKey="network"/>
               <menuitem label="&btnConsoleWarnings;" type="checkbox" autocheck="false"
                         prefKey="netwarn"/>
+              <menuitem label="&btnConsoleXhr;" type="checkbox" autocheck="false"
+                        prefKey="netxhr"/>
               <menuitem label="&btnConsoleLog;" type="checkbox" autocheck="false"
                         prefKey="networkinfo"/>
               <menuseparator id="saveBodiesSeparator" />
               <menuitem id="saveBodies" type="checkbox" label="&saveBodies.label;"
                         accesskey="&saveBodies.accesskey;"/>
             </menupopup>
           </toolbarbutton>
           <toolbarbutton label="&btnPageCSS.label;" type="menu-button"
--- a/browser/devtools/webide/modules/app-manager.js
+++ b/browser/devtools/webide/modules/app-manager.js
@@ -505,16 +505,22 @@ let AppManager = exports.AppManager = {
           origin: origin.spec,
           manifestURL: project.location
         };
         response = yield self._appsFront.installHosted(appId,
                                             metadata,
                                             project.manifest);
       }
 
+      // Addons don't have any document to load (yet?)
+      // So that there is no need to run them, installing is enough
+      if (project.manifest.role && project.manifest.role === "addon") {
+        return;
+      }
+
       let {app} = response;
       if (!app.running) {
         let deferred = promise.defer();
         self.on("app-manager-update", function onUpdate(event, what) {
           if (what == "project-is-running") {
             self.off("app-manager-update", onUpdate);
             deferred.resolve();
           }
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -281,20 +281,16 @@ offlineApps.never=Never for This Site
 offlineApps.neverAccessKey=e
 offlineApps.notNow=Not Now
 offlineApps.notNowAccessKey=N
 
 offlineApps.usage=This website (%S) is now storing more than %SMB of data on your computer for offline use.
 offlineApps.manageUsage=Show settings
 offlineApps.manageUsageAccessKey=S
 
-# LOCALIZATION NOTE (indexedDB.usage): %1$S is the website host name
-# %2$S a number of megabytes.
-indexedDB.usage=This website (%1$S) is attempting to store more than %2$S MB of data on your computer for offline use.
-
 identity.identified.verifier=Verified by: %S
 identity.identified.verified_by_you=You have added a security exception for this site.
 identity.identified.state_and_country=%S, %S
 
 identity.encrypted2=The connection to this website is secure.
 identity.broken_loaded=The connection to this website is not fully secure because it contains unencrypted elements (such as images) or the encryption is not strong enough.
 identity.mixed_active_loaded2=This website contains interactive content that isn't encrypted (such as scripts). Other people can view your information or modify the website's behavior.
 identity.unencrypted=Your connection to this website is not encrypted.
--- a/browser/locales/en-US/chrome/browser/devtools/netmonitor.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/netmonitor.dtd
@@ -37,18 +37,24 @@
 <!-- LOCALIZATION NOTE (netmonitorUI.toolbar.domain): This is the label displayed
   -  in the network table toolbar, above the "domain" column. -->
 <!ENTITY netmonitorUI.toolbar.domain      "Domain">
 
 <!-- LOCALIZATION NOTE (netmonitorUI.toolbar.type): This is the label displayed
   -  in the network table toolbar, above the "type" column. -->
 <!ENTITY netmonitorUI.toolbar.type        "Type">
 
+<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.transferred): This is the label displayed
+  -  in the network table toolbar, above the "transferred" column, which is the
+  -  compressed / encoded size. -->
+<!ENTITY netmonitorUI.toolbar.transferred "Transferred">
+
 <!-- LOCALIZATION NOTE (netmonitorUI.toolbar.size): This is the label displayed
-  -  in the network table toolbar, above the "size" column. -->
+  -  in the network table toolbar, above the "size" column, which is the
+  -  uncompressed / decoded size. -->
 <!ENTITY netmonitorUI.toolbar.size        "Size">
 
 <!-- LOCALIZATION NOTE (netmonitorUI.toolbar.waterfall): This is the label displayed
   -  in the network table toolbar, above the "waterfall" column. -->
 <!ENTITY netmonitorUI.toolbar.waterfall   "Timeline">
 
 <!-- LOCALIZATION NOTE (debuggerUI.tab.headers): This is the label displayed
   -  in the network details pane identifying the headers tab. -->
--- a/browser/locales/en-US/chrome/browser/devtools/netmonitor.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/netmonitor.properties
@@ -164,16 +164,21 @@ networkMenu.empty=No requests
 # information about all requests. Parameters: #1 is the number of requests,
 # #2 is the size, #3 is the number of seconds.
 networkMenu.summary=One request, #2 KB, #3 s;#1 requests, #2 KB, #3 s
 
 # LOCALIZATION NOTE (networkMenu.sizeKB): This is the label displayed
 # in the network menu specifying the size of a request (in kilobytes).
 networkMenu.sizeKB=%S KB
 
+# LOCALIZATION NOTE (networkMenu.sizeUnavailable): This is the label displayed
+# in the network menu specifying the transferred size of a request is
+# unavailable.
+networkMenu.sizeUnavailable=—
+
 # LOCALIZATION NOTE (networkMenu.totalMS): This is the label displayed
 # in the network menu specifying the time for a request to finish (in milliseconds).
 networkMenu.totalMS=→ %S ms
 
 # LOCALIZATION NOTE (networkMenu.millisecond): This is the label displayed
 # in the network menu specifying timing interval divisions (in milliseconds).
 networkMenu.millisecond=%S ms
 
--- a/browser/locales/en-US/chrome/browser/devtools/webConsole.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/webConsole.dtd
@@ -68,16 +68,17 @@
   -  console.error(). -->
 <!ENTITY btnPageLogging.label   "Logging">
 <!ENTITY btnPageLogging.tooltip "Log messages sent to the window.console object">
 <!ENTITY btnPageLogging.accesskey3 "L">
 <!ENTITY btnConsoleErrors       "Errors">
 <!ENTITY btnConsoleInfo         "Info">
 <!ENTITY btnConsoleWarnings     "Warnings">
 <!ENTITY btnConsoleLog          "Log">
+<!ENTITY btnConsoleXhr          "XHR">
 <!ENTITY btnConsoleReflows      "Reflows">
 
 <!ENTITY filterOutput.placeholder "Filter output">
 <!ENTITY btnClear.label        "Clear">
 <!ENTITY btnClear.tooltip      "Clear the Web Console output">
 <!ENTITY btnClear.accesskey    "r">
 
 <!ENTITY fullZoomEnlargeCmd.commandkey  "+">
--- a/browser/locales/en-US/chrome/browser/devtools/webaudioeditor.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/webaudioeditor.dtd
@@ -18,19 +18,19 @@
 <!-- LOCALIZATION NOTE (webAudioEditorUI.reloadNotice2): This is the label shown
   -  along with the button that triggers a page refresh. -->
 <!ENTITY webAudioEditorUI.reloadNotice2   "the page to view and edit the audio context.">
 
 <!-- LOCALIZATION NOTE (webAudioEditorUI.emptyNotice): This is the label shown
   -  while the page is refreshing and the tool waits for a audio context. -->
 <!ENTITY webAudioEditorUI.emptyNotice     "Waiting for an audio context to be created…">
 
-<!-- LOCALIZATION NOTE (webAudioEditorUI.tab.properties): This is the label shown
+<!-- LOCALIZATION NOTE (webAudioEditorUI.tab.properties2): This is the label shown
   -  for the properties tab view. -->
-<!ENTITY webAudioEditorUI.tab.properties  "Parameters">
+<!ENTITY webAudioEditorUI.tab.properties2 "Properties">
 
 <!-- LOCALIZATION NOTE (webAudioEditorUI.tab.automation): This is the label shown
   -  for the automation tab view. -->
 <!ENTITY webAudioEditorUI.tab.automation  "Automation">
 
 <!-- LOCALIZATION NOTE (webAudioEditorUI.inspectorTitle): This is the title for the
   -  AudioNode inspector view. -->
 <!ENTITY webAudioEditorUI.inspectorTitle  "AudioNode Inspector">
--- a/browser/metro/base/content/bindings/browser.js
+++ b/browser/metro/base/content/bindings/browser.js
@@ -702,46 +702,35 @@ ContentActive.init();
  * the observer service for events regarding IndexedDB
  * prompts, and sends messages to the parent to actually
  * show the prompts.
  */
 let IndexedDB = {
   _permissionsPrompt: "indexedDB-permissions-prompt",
   _permissionsResponse: "indexedDB-permissions-response",
 
-  _quotaPrompt: "indexedDB-quota-prompt",
-  _quotaResponse: "indexedDB-quota-response",
-  _quotaCancel: "indexedDB-quota-cancel",
-
   waitingObservers: [],
 
   init: function IndexedDBPromptHelper_init() {
     let os = Services.obs;
     os.addObserver(this, this._permissionsPrompt, false);
-    os.addObserver(this, this._quotaPrompt, false);
-    os.addObserver(this, this._quotaCancel, false);
     addMessageListener("IndexedDB:Response", this);
   },
 
   observe: function IndexedDBPromptHelper_observe(aSubject, aTopic, aData) {
-    if (aTopic != this._permissionsPrompt && aTopic != this._quotaPrompt && aTopic != this._quotaCancel) {
+    if (aTopic != this._permissionsPrompt) {
       throw new Error("Unexpected topic!");
     }
 
     let requestor = aSubject.QueryInterface(Ci.nsIInterfaceRequestor);
     let observer = requestor.getInterface(Ci.nsIObserver);
 
     let contentWindow = requestor.getInterface(Ci.nsIDOMWindow);
     let contentDocument = contentWindow.document;
 
-    if (aTopic == this._quotaCancel) {
-      observer.observe(null, this._quotaResponse, Ci.nsIPermissionManager.UNKNOWN_ACTION);
-      return;
-    }
-
     // Remote to parent
     sendAsyncMessage("IndexedDB:Prompt", {
       topic: aTopic,
       host: contentDocument.documentURIObject.asciiHost,
       location: contentDocument.location.toString(),
       data: aData,
       observerId: this.addWaitingObserver(observer)
     });
--- a/browser/metro/base/content/helperui/IndexedDB.js
+++ b/browser/metro/base/content/helperui/IndexedDB.js
@@ -5,20 +5,16 @@
 /**
  * Helper class for IndexedDB, parent part. Listens to
  * messages from the child and shows prompts for them.
  */
 let IndexedDB = {
   _permissionsPrompt: "indexedDB-permissions-prompt",
   _permissionsResponse: "indexedDB-permissions-response",
 
-  _quotaPrompt: "indexedDB-quota-prompt",
-  _quotaResponse: "indexedDB-quota-response",
-  _quotaCancel: "indexedDB-quota-cancel",
-
   _notificationIcon: "indexedDB-notification-icon",
 
   receiveMessage: function(aMessage) {
     switch (aMessage.name) {
       case "IndexedDB:Prompt":
         this.showPrompt(aMessage);
     }
   },
@@ -28,24 +24,16 @@ let IndexedDB = {
     let payload = aMessage.json;
     let host = payload.host;
     let topic = payload.topic;
     let type;
 
     if (topic == this._permissionsPrompt) {
       type = "indexedDB";
       payload.responseTopic = this._permissionsResponse;
-    } else if (topic == this._quotaPrompt) {
-      type = "indexedDBQuota";
-      payload.responseTopic = this._quotaResponse;
-    } else if (topic == this._quotaCancel) {
-      payload.permission = Ci.nsIPermissionManager.UNKNOWN_ACTION;
-      browser.messageManager.sendAsyncMessage("IndexedDB:Response", payload);
-      // XXX Need to actually save this?
-      return;
     }
 
     let prompt = Cc["@mozilla.org/content-permission/prompt;1"].createInstance(Ci.nsIContentPermissionPrompt);
     let types = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
     let promptType = {
       type: type,
       access: "unused",
       QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType])
--- a/browser/metro/components/ContentPermissionPrompt.js
+++ b/browser/metro/components/ContentPermissionPrompt.js
@@ -8,18 +8,17 @@ const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 const kCountBeforeWeRemember = 5;
 
 const kEntities = {
   "geolocation": "geolocation2",
-  "indexedDB": "offlineApps",
-  "indexedDBQuota": "indexedDBQuota"
+  "indexedDB": "offlineApps"
 };
 
 const kIcons = {
   geolocation: "chrome://browser/skin/images/infobar-geolocation.png"
 };
 
 function ContentPermissionPrompt() {}
 
--- a/browser/metro/locales/en-US/chrome/browser.properties
+++ b/browser/metro/locales/en-US/chrome/browser.properties
@@ -102,34 +102,30 @@ popupButtonNeverWarn3=Never allow
 contentPermissions.alwaysForSite=Always for this site
 contentPermissions.neverForSite=Never for this site
 
 # Geolocation UI
 # LOCALIZATION NOTE (geolocation2.allow): If you're having trouble with the
 # word Share, please use Allow and Block in your language.
 geolocation2.allow=Share location
 
-# LOCALIZATION NOTE (geolocation2.wantsTo offlineApps.wantsTo indexedDBQuota.wantsTo):
+# LOCALIZATION NOTE (geolocation2.wantsTo offlineApps.wantsTo):
 # %S is the domain name of the web site.
 geolocation2.wantsTo=Share your location with %S?
 
 geolocation.learnMore=Learn more…
 
 # Error Console
 typeError=Error:
 typeWarning=Warning:
 
 # Offline web applications
 offlineApps.allow=Allow
 offlineApps.wantsTo=%S wants to store data on your device for offline use.
 
-# IndexedDB Quota increases
-indexedDBQuota.allow=Allow
-indexedDBQuota.wantsTo=%S wants to store a lot of data on your device for offline use.
-
 tabs.emptyTabTitle=New Tab
 
 # Open Search
 # LOCALIZATION NOTE (opensearch.search.header): %S is the word or phrase
 # typed by the user in the urlbar to search
 opensearch.search.header=Search for “%S” on:
 
 # Check for Updates in the About Panel - button labels and accesskeys
--- a/browser/metro/profile/metro.js
+++ b/browser/metro/profile/metro.js
@@ -406,17 +406,17 @@ pref("plugins.force.wmode", "opaque");
 // 3 - Last 4 Hours
 // 4 - Today
 pref("privacy.sanitize.timeSpan", 1);
 pref("privacy.sanitize.sanitizeOnShutdown", false);
 pref("privacy.sanitize.migrateFx3Prefs",    false);
 
 // enable geo
 pref("geo.enabled", true);
-pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%GOOGLE_API_KEY%");
+pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
 
 // snapped view
 pref("browser.ui.snapped.maxWidth", 600);
 
 // kinetic tweakables
 pref("browser.ui.kinetic.updateInterval", 16);
 pref("browser.ui.kinetic.exponentialC", 1400);
 pref("browser.ui.kinetic.polynomialC", 100);
--- a/browser/modules/SitePermissions.jsm
+++ b/browser/modules/SitePermissions.jsm
@@ -80,33 +80,25 @@ this.SitePermissions = {
       return;
 
     if (aState == this.UNKNOWN) {
       this.remove(aURI, aPermissionID);
       return;
     }
 
     Services.perms.add(aURI, aPermissionID, aState);
-
-    if (aPermissionID in gPermissionObject &&
-        gPermissionObject[aPermissionID].onChange)
-      gPermissionObject[aPermissionID].onChange(aURI, aState);
   },
 
   /* Removes the saved state of a particular permission for a given URI.
    */
   remove: function (aURI, aPermissionID) {
     if (!this.isSupportedURI(aURI))
       return;
 
     Services.perms.remove(aURI.host, aPermissionID);
-
-    if (aPermissionID in gPermissionObject &&
-        gPermissionObject[aPermissionID].onChange)
-      gPermissionObject[aPermissionID].onChange(aURI, this.UNKNOWN);
   },
 
   /* Returns the localized label for the permission with the given ID, to be
    * used in a UI for managing permissions.
    */
   getPermissionLabel: function (aPermissionID) {
     return gStringBundle.GetStringFromName("permission." + aPermissionID + ".label");
   },
@@ -139,19 +131,16 @@ let gPermissionObject = {
    *    Allows sub domains to have their own permissions.
    *    Defaults to false.
    *
    *  - getDefault
    *    Called to get the permission's default state.
    *    Defaults to UNKNOWN, indicating that the user will be asked each time
    *    a page asks for that permissions.
    *
-   *  - onChange
-   *    Called when a permission state changes.
-   *
    *  - states
    *    Array of permission states to be exposed to the user.
    *    Defaults to ALLOW, BLOCK and the default state (see getDefault).
    */
 
   "image": {
     getDefault: function () {
       return Services.prefs.getIntPref("permissions.default.image") == 2 ?
@@ -190,21 +179,16 @@ let gPermissionObject = {
                SitePermissions.BLOCK : SitePermissions.ALLOW;
     }
   },
 
   "geo": {
     exactHostMatch: true
   },
 
-  "indexedDB": {
-    onChange: function (aURI, aState) {
-      if (aState == SitePermissions.BLOCK)
-        Services.perms.remove(aURI.host, "indexedDB-unlimited");
-    }
-  },
+  "indexedDB": {},
 
   "fullscreen": {},
 
   "pointerLock": {
     exactHostMatch: true
   }
 };
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1180,17 +1180,16 @@ toolbarbutton[sdk-button="true"][cui-are
   margin: 0;
   -moz-margin-start: 5px;
   min-height: 0;
   min-width: 0;
   list-style-image: url("moz-icon://stock/gtk-cancel?size=menu");
 }
 
 .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
-.popup-notification-icon[popupid="indexedDB-quota-prompt"],
 .popup-notification-icon[popupid*="offline-app-requested"],
 .popup-notification-icon[popupid="offline-app-usage"] {
   list-style-image: url(chrome://global/skin/icons/question-64.png);
 }
 
 .popup-notification-icon[popupid="password-save"],
 .popup-notification-icon[popupid="password-change"] {
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -4165,17 +4165,16 @@ menulist.translate-infobar-element > .me
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 .popup-progress-cancel:active {
   -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 
 .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
-.popup-notification-icon[popupid="indexedDB-quota-prompt"],
 .popup-notification-icon[popupid*="offline-app-requested"],
 .popup-notification-icon[popupid="offline-app-usage"] {
   list-style-image: url(chrome://global/skin/icons/question-64.png);
 }
 
 .popup-notification-icon[popupid="password-save"],
 .popup-notification-icon[popupid="password-change"] {
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
--- a/browser/themes/shared/devtools/netmonitor.inc.css
+++ b/browser/themes/shared/devtools/netmonitor.inc.css
@@ -188,16 +188,21 @@
   width: 4em;
 }
 
 .requests-menu-size {
   text-align: center;
   width: 8em;
 }
 
+.requests-menu-transferred {
+  text-align: center;
+  width: 8em;
+}
+
 /* Network requests table: status codes */
 
 box.requests-menu-status {
   background: #fff;
   width: 10px;
   -moz-margin-start: 5px;
   -moz-margin-end: 5px;
   border-radius: 10px;
--- a/browser/themes/shared/devtools/webaudioeditor.inc.css
+++ b/browser/themes/shared/devtools/webaudioeditor.inc.css
@@ -138,16 +138,22 @@ text {
 .nodes text {
   cursor: pointer;
 }
 
 /**
  * Inspector Styles
  */
 
+/* hide the variables view scope title as its redundant,
+ * because there's only one scope displayed. */
+.variables-view-scope > .title {
+  display: none;
+}
+
 #web-audio-inspector-title {
   margin: 6px;
 }
 
 .web-audio-inspector .error {
   background-image: url(alerticon-warning.png);
   background-size: 13px 12px;
   -moz-appearance: none;
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -136,16 +136,20 @@ treecol {
 #applicationsContent {
   padding: 15px 0;
 }
 
 #filter {
   -moz-margin-start: 0;
 }
 
+#handlersView {
+  height: 25em;
+}
+
 #handlersView > richlistitem {
   min-height: 36px !important;
 }
 
 .typeIcon {
   -moz-margin-start: 10px !important;
   -moz-margin-end: 9px !important;
 }
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -2195,17 +2195,16 @@ toolbarbutton.bookmark-item[dragover="tr
   -moz-image-region: rect(16px, 32px, 32px, 16px);
 }
 
 .popup-progress-cancel:active {
   -moz-image-region: rect(32px, 32px, 48px, 16px);
 }
 
 .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
-.popup-notification-icon[popupid="indexedDB-quota-prompt"],
 .popup-notification-icon[popupid*="offline-app-requested"],
 .popup-notification-icon[popupid="offline-app-usage"] {
   list-style-image: url(chrome://global/skin/icons/question-64.png);
 }
 
 .popup-notification-icon[popupid="password-save"],
 .popup-notification-icon[popupid="password-change"] {
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
--- a/configure.in
+++ b/configure.in
@@ -3000,17 +3000,17 @@ then
     AC_SUBST(MOZ_USE_PTHREADS)
 fi
 
 
 dnl Checks for library functions.
 dnl ========================================================
 AC_PROG_GCC_TRADITIONAL
 AC_FUNC_MEMCMP
-AC_CHECK_FUNCS(stat64 lstat64 truncate64 statvfs64 statvfs statfs64 statfs getpagesize localtime_r arc4random arc4random_buf)
+AC_CHECK_FUNCS(stat64 lstat64 truncate64 statvfs64 statvfs statfs64 statfs getpagesize gmtime_r localtime_r arc4random arc4random_buf)
 
 dnl check for clock_gettime(), the CLOCK_MONOTONIC clock
 AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC),
                ac_cv_clock_monotonic,
                [for libs in "" -lrt; do
                     _SAVE_LIBS="$LIBS"
                     LIBS="$LIBS $libs"
                     AC_TRY_LINK([#include <time.h>],
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -12866,19 +12866,26 @@ nsDocShell::GetTopFrameElement(nsIDOMEle
     if (!win) {
         return NS_OK;
     }
 
     nsCOMPtr<nsIDOMWindow> top;
     win->GetScriptableTop(getter_AddRefs(top));
     NS_ENSURE_TRUE(top, NS_ERROR_FAILURE);
 
-    // GetFrameElement, /not/ GetScriptableFrameElement -- if |top| is inside
-    // <iframe mozbrowser>, we want to return the iframe, not null.
-    return top->GetFrameElement(aElement);
+    nsCOMPtr<nsPIDOMWindow> piTop = do_QueryInterface(top);
+    NS_ENSURE_TRUE(piTop, NS_ERROR_FAILURE);
+
+    // GetFrameElementInternal, /not/ GetScriptableFrameElement -- if |top| is
+    // inside <iframe mozbrowser>, we want to return the iframe, not null.
+    // And we want to cross the content/chrome boundary.
+    nsCOMPtr<nsIDOMElement> elt =
+        do_QueryInterface(piTop->GetFrameElementInternal());
+    elt.forget(aElement);
+    return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetNestedFrameId(uint64_t* aId)
 {
     *aId = 0;
     return NS_OK;
 }
--- a/docshell/base/nsILoadContext.idl
+++ b/docshell/base/nsILoadContext.idl
@@ -30,21 +30,24 @@ interface nsILoadContext : nsISupports
    * topWindow is the top window which is of same type as associatedWindow.
    * This is equivalent to associatedWindow.top, but is provided here as a
    * convenience.  All the same caveats as associatedWindow of apply, of
    * course.  This attribute may be null if there is no associated window.
    */
   readonly attribute nsIDOMWindow topWindow;
 
   /**
-   * topFrameElement is the <iframe> or <frame> element which contains the
-   * topWindow with which the load is associated.
+   * topFrameElement is the <iframe>, <frame>, or <browser> element which
+   * contains the topWindow with which the load is associated.
    *
    * Note that we may have a topFrameElement even when we don't have an
    * associatedWindow, if the topFrameElement's content lives out of process.
+   * topFrameElement is available in single-process and multiprocess contexts.
+   * Note that topFrameElement may be in chrome even when the nsILoadContext is
+   * associated with content.
    */
   readonly attribute nsIDOMElement topFrameElement;
 
   /**
    * If this LoadContext corresponds to a nested remote iframe, we don't have
    * access to the topFrameElement.  Instead, we must use this id to send
    * messages. A return value of 0 signifies that this load context is not for
    * a nested frame.
--- a/dom/apps/PermissionsTable.jsm
+++ b/dom/apps/PermissionsTable.jsm
@@ -301,25 +301,16 @@ this.PermissionsTable =  { geolocation: 
                              certified: ALLOW_ACTION
                            },
                            "embed-widgets": {
                              app: DENY_ACTION,
                              trusted: DENY_ACTION,
                              privileged: ALLOW_ACTION,
                              certified: ALLOW_ACTION
                            },
-                           "storage": {
-                             app: ALLOW_ACTION,
-                             trusted: ALLOW_ACTION,
-                             privileged: ALLOW_ACTION,
-                             certified: ALLOW_ACTION,
-                             substitute: [
-                               "indexedDB-unlimited"
-                             ]
-                           },
                            "background-sensors": {
                              app: DENY_ACTION,
                              trusted: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
                            cellbroadcast: {
                              app: DENY_ACTION,
--- a/dom/asmjscache/AsmJSCache.cpp
+++ b/dom/asmjscache/AsmJSCache.cpp
@@ -496,17 +496,16 @@ public:
   : mPrincipal(aPrincipal),
     mOpenMode(aOpenMode),
     mWriteParams(aWriteParams),
     mNeedAllowNextSynchronizedOp(false),
     mPersistence(quota::PERSISTENCE_TYPE_INVALID),
     mState(eInitial),
     mResult(JS::AsmJSCache_InternalError),
     mIsApp(false),
-    mHasUnlimStoragePerm(false),
     mEnforcingQuota(true)
   {
     MOZ_ASSERT(IsMainProcess());
   }
 
   virtual ~MainProcessRunnable()
   {
     MOZ_ASSERT(mState == eFinished);
@@ -670,17 +669,16 @@ private:
     eClosing, // Waiting to be dispatched to main thread again
     eFailing, // Just failed, waiting to be dispatched to the main thread
     eFinished, // Terminal state
   };
   State mState;
   JS::AsmJSCacheResult mResult;
 
   bool mIsApp;
-  bool mHasUnlimStoragePerm;
   bool mEnforcingQuota;
 };
 
 void
 MainProcessRunnable::InitPersistenceType()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mState == eInitial);
@@ -695,17 +693,17 @@ MainProcessRunnable::InitPersistenceType
     // entry and avoids all the issues around the persistent quota prompt.
     // If quota is enforced for the app, then we can still cache in temporary
     // for a likely good first-run experience.
 
     MOZ_ASSERT_IF(mWriteParams.mInstalled, mIsApp);
 
     if (mWriteParams.mInstalled &&
         !QuotaManager::IsQuotaEnforced(quota::PERSISTENCE_TYPE_PERSISTENT,
-                                       mOrigin, mIsApp, mHasUnlimStoragePerm)) {
+                                       mOrigin, mIsApp)) {
       mPersistence = quota::PERSISTENCE_TYPE_PERSISTENT;
     } else {
       mPersistence = quota::PERSISTENCE_TYPE_TEMPORARY;
     }
 
     return;
   }
 
@@ -730,25 +728,23 @@ MainProcessRunnable::InitOnMainThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mState == eInitial);
 
   QuotaManager* qm = QuotaManager::GetOrCreate();
   NS_ENSURE_STATE(qm);
 
   nsresult rv =
-    QuotaManager::GetInfoFromPrincipal(mPrincipal, &mGroup, &mOrigin, &mIsApp,
-                                       &mHasUnlimStoragePerm);
+    QuotaManager::GetInfoFromPrincipal(mPrincipal, &mGroup, &mOrigin, &mIsApp);
   NS_ENSURE_SUCCESS(rv, rv);
 
   InitPersistenceType();
 
   mEnforcingQuota =
-    QuotaManager::IsQuotaEnforced(mPersistence, mOrigin, mIsApp,
-                                  mHasUnlimStoragePerm);
+    QuotaManager::IsQuotaEnforced(mPersistence, mOrigin, mIsApp);
 
   QuotaManager::GetStorageId(mPersistence, mOrigin, quota::Client::ASMJS,
                              NS_LITERAL_STRING("asmjs"), mStorageId);
 
   return NS_OK;
 }
 
 nsresult
@@ -757,17 +753,16 @@ MainProcessRunnable::ReadMetadata()
   AssertIsOnIOThread();
   MOZ_ASSERT(mState == eReadyToReadMetadata);
 
   QuotaManager* qm = QuotaManager::Get();
   MOZ_ASSERT(qm, "We are on the QuotaManager's IO thread");
 
   nsresult rv =
     qm->EnsureOriginIsInitialized(mPersistence, mGroup, mOrigin, mIsApp,
-                                  mHasUnlimStoragePerm,
                                   getter_AddRefs(mDirectory));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mDirectory->Append(NS_LITERAL_STRING(ASMJSCACHE_DIRECTORY_NAME));
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool exists;
   rv = mDirectory->Exists(&exists);
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3615,24 +3615,26 @@ nsContentUtils::DispatchUntrustedEvent(n
                        false, aDefaultAction);
 }
 
 // static
 nsresult
 nsContentUtils::DispatchEvent(nsIDocument* aDoc, nsISupports* aTarget,
                               const nsAString& aEventName,
                               bool aCanBubble, bool aCancelable,
-                              bool aTrusted, bool *aDefaultAction)
+                              bool aTrusted, bool *aDefaultAction,
+                              bool aOnlyChromeDispatch)
 {
   nsCOMPtr<nsIDOMEvent> event;
   nsCOMPtr<EventTarget> target;
   nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble,
                                   aCancelable, aTrusted, getter_AddRefs(event),
                                   getter_AddRefs(target));
   NS_ENSURE_SUCCESS(rv, rv);
+  event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = aOnlyChromeDispatch;
 
   bool dummy;
   return target->DispatchEvent(event, aDefaultAction ? aDefaultAction : &dummy);
 }
 
 nsresult
 nsContentUtils::DispatchChromeEvent(nsIDocument *aDoc,
                                     nsISupports *aTarget,
@@ -3659,16 +3661,27 @@ nsContentUtils::DispatchChromeEvent(nsID
   nsEventStatus status = nsEventStatus_eIgnore;
   rv = piTarget->DispatchDOMEvent(nullptr, event, nullptr, &status);
   if (aDefaultAction) {
     *aDefaultAction = (status != nsEventStatus_eConsumeNoDefault);
   }
   return rv;
 }
 
+nsresult
+nsContentUtils::DispatchEventOnlyToChrome(nsIDocument* aDoc,
+                                          nsISupports* aTarget,
+                                          const nsAString& aEventName,
+                                          bool aCanBubble, bool aCancelable,
+                                          bool* aDefaultAction)
+{
+  return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
+                       true, aDefaultAction, true);
+}
+
 /* static */
 Element*
 nsContentUtils::MatchElementId(nsIContent *aContent, const nsIAtom* aId)
 {
   for (nsIContent* cur = aContent;
        cur;
        cur = cur->GetNextNode(aContent)) {
     if (aId == cur->GetID()) {
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -982,17 +982,20 @@ public:
                                          nsISupports* aTarget,
                                          const nsAString& aEventName,
                                          bool aCanBubble,
                                          bool aCancelable,
                                          bool *aDefaultAction = nullptr);
 
   /**
    * This method creates and dispatches a trusted event to the chrome
-   * event handler.
+   * event handler (the parent object of the DOM Window in the event target
+   * chain). Note, chrome event handler is used even if aTarget is a chrome
+   * object. Use DispatchEventOnlyToChrome if the normal event dispatching is
+   * wanted in case aTarget is a chrome object.
    * Works only with events which can be created by calling
    * nsIDOMDocument::CreateEvent() with parameter "Events".
    * @param aDocument      The document which will be used to create the event,
    *                       and whose window's chrome handler will be used to
    *                       dispatch the event.
    * @param aTarget        The target of the event, used for event->SetTarget()
    * @param aEventName     The name of the event.
    * @param aCanBubble     Whether the event can bubble.
@@ -1002,16 +1005,42 @@ public:
    */
   static nsresult DispatchChromeEvent(nsIDocument* aDoc,
                                       nsISupports* aTarget,
                                       const nsAString& aEventName,
                                       bool aCanBubble,
                                       bool aCancelable,
                                       bool *aDefaultAction = nullptr);
 
+
+  /**
+   * This method creates and dispatches a trusted event.
+   * If aTarget is not a chrome object, the nearest chrome object in the
+   * propagation path will be used as the start of the event target chain.
+   * This method is different than DispatchChromeEvent, which always dispatches
+   * events to chrome event handler. DispatchEventOnlyToChrome works like
+   * DispatchTrustedEvent in the case aTarget is a chrome object.
+   * Works only with events which can be created by calling
+   * nsIDOMDocument::CreateEvent() with parameter "Events".
+   * @param aDoc           The document which will be used to create the event.
+   * @param aTarget        The target of the event, should be QIable to
+   *                       nsIDOMEventTarget.
+   * @param aEventName     The name of the event.
+   * @param aCanBubble     Whether the event can bubble.
+   * @param aCancelable    Is the event cancelable.
+   * @param aDefaultAction Set to true if default action should be taken,
+   *                       see nsIDOMEventTarget::DispatchEvent.
+   */
+  static nsresult DispatchEventOnlyToChrome(nsIDocument* aDoc,
+                                            nsISupports* aTarget,
+                                            const nsAString& aEventName,
+                                            bool aCanBubble,
+                                            bool aCancelable,
+                                            bool *aDefaultAction = nullptr);
+
   /**
    * Determines if an event attribute name (such as onclick) is valid for
    * a given element type. Types are from the EventNameType enumeration
    * defined above.
    *
    * @param aName the event name to look up
    * @param aType the type of content
    */
@@ -1247,17 +1276,17 @@ public:
 
   /**
    * Utility method that checks if a given node has any non-empty children. This
    * method does not descend recursively into children by default.
    *
    * @param aDiscoverMode Set to eRecurseIntoChildren to descend recursively
    * into children.
    */
-  enum TextContentDiscoverMode MOZ_ENUM_TYPE(uint8_t) {
+  enum TextContentDiscoverMode : uint8_t {
     eRecurseIntoChildren, eDontRecurseIntoChildren
   };
 
   static bool HasNonEmptyTextContent(
     nsINode* aNode,
     TextContentDiscoverMode aDiscoverMode = eDontRecurseIntoChildren);
 
   /**
@@ -2041,17 +2070,17 @@ public:
    * NOTE: the caller has to make sure autocomplete makes sense for the
    * element's type.
    *
    * @param aInput the input element to check. NOTE: aInput can't be null.
    * @return whether the input element has autocomplete enabled.
    */
   static bool IsAutocompleteEnabled(nsIDOMHTMLInputElement* aInput);
 
-  enum AutocompleteAttrState MOZ_ENUM_TYPE(uint8_t)
+  enum AutocompleteAttrState : uint8_t
   {
     eAutocompleteAttrState_Unknown = 1,
     eAutocompleteAttrState_Invalid,
     eAutocompleteAttrState_Valid,
   };
   /**
    * Parses the value of the autocomplete attribute into aResult, ensuring it's
    * composed of valid tokens, otherwise the value "" is used.
@@ -2248,17 +2277,18 @@ private:
                              bool aAllowWrapping);
 
   static nsresult DispatchEvent(nsIDocument* aDoc,
                                 nsISupports* aTarget,
                                 const nsAString& aEventName,
                                 bool aCanBubble,
                                 bool aCancelable,
                                 bool aTrusted,
-                                bool *aDefaultAction = nullptr);
+                                bool *aDefaultAction = nullptr,
+                                bool aOnlyChromeDispatch = false);
 
   static void InitializeModifierStrings();
 
   static void DropFragmentParsers();
 
   static bool MatchClassNames(nsIContent* aContent, int32_t aNamespaceID,
                               nsIAtom* aAtom, void* aData);
   static void DestroyClassNameArray(void* aData);
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -3146,18 +3146,17 @@ nsDOMWindowUtils::GetFileReferences(cons
 {
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
 
   nsCString origin;
   nsresult rv =
-    quota::QuotaManager::GetInfoFromWindow(window, nullptr, &origin, nullptr,
-                                           nullptr);
+    quota::QuotaManager::GetInfoFromWindow(window, nullptr, &origin, nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
   IDBOpenDBOptions options;
   JS::Rooted<JS::Value> optionsVal(aCx, aOptions);
   if (!options.Init(aCx, optionsVal)) {
     return NS_ERROR_TYPE_ERR;
   }
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3612,17 +3612,17 @@ nsDocument::SetBaseURI(nsIURI* aURI)
       return NS_OK;
     }
   }
 
   // Check if CSP allows this base-uri
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   nsresult rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
   NS_ENSURE_SUCCESS(rv, rv);
-  if (csp) {
+  if (csp && aURI) {
     bool permitsBaseURI = false;
 
     // base-uri is only enforced if explicitly defined in the
     // policy - do *not* consult default-src, see:
     // http://www.w3.org/TR/CSP2/#directive-default-src
     rv = csp->Permits(aURI, nsIContentSecurityPolicy::BASE_URI_DIRECTIVE,
                       true, &permitsBaseURI);
     NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1140,21 +1140,22 @@ nsFocusManager::ActivateOrDeactivate(nsP
     return;
   }
 
   // Inform the DOM window that it has activated or deactivated, so that
   // the active attribute is updated on the window.
   aWindow->ActivateOrDeactivate(aActive);
 
   // Send the activate event.
-  nsContentUtils::DispatchTrustedEvent(aWindow->GetExtantDoc(),
-                                       aWindow,
-                                       aActive ? NS_LITERAL_STRING("activate") :
-                                                 NS_LITERAL_STRING("deactivate"),
-                                       true, true, nullptr);
+  nsContentUtils::DispatchEventOnlyToChrome(aWindow->GetExtantDoc(),
+                                            aWindow,
+                                            aActive ?
+                                              NS_LITERAL_STRING("activate") :
+                                              NS_LITERAL_STRING("deactivate"),
+                                            true, true, nullptr);
 
   // Look for any remote child frames, iterate over them and send the activation notification.
   nsContentUtils::CallOnAllRemoteChildren(aWindow, ActivateOrDeactivateChild,
                                           (void *)aActive);
 }
 
 void
 nsFocusManager::SetFocusInner(nsIContent* aNewContent, int32_t aFlags,
--- a/dom/base/nsFocusManager.h
+++ b/dom/base/nsFocusManager.h
@@ -94,20 +94,16 @@ public:
 
   /**
    * Update the caret with current mode (whether in caret browsing mode or not).
    */
   void UpdateCaretForCaretBrowsingMode();
 
   bool IsParentActivated()
   {
-    if (mParentFocusType == ParentFocusType_Ignore) {
-      return mActiveWindow != nullptr;
-    }
-
     return mParentFocusType == ParentFocusType_Active;
   }
 
   /**
    * Returns the content node that would be focused if aWindow was in an
    * active window. This will traverse down the frame hierarchy, starting at
    * the given window aWindow. Sets aFocusedWindow to the window with the
    * document containing aFocusedContent. If no element is focused,
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -13261,17 +13261,22 @@ nsGlobalWindow::AddSizeOfIncludingThis(n
     EventListenerManager* elm = GetExistingListenerManager();
     if (elm) {
       aWindowSizes->mDOMOtherSize +=
         elm->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
       aWindowSizes->mDOMEventListenersCount +=
         elm->ListenerCount();
     }
     if (mDoc) {
-      mDoc->DocAddSizeOfIncludingThis(aWindowSizes);
+      // Multiple global windows can share a document. So only measure the
+      // document if it (a) doesn't have a global window, or (b) it's the
+      // primary document for the window.
+      if (!mDoc->GetInnerWindow() || mDoc->GetInnerWindow() == this) {
+        mDoc->DocAddSizeOfIncludingThis(aWindowSizes);
+      }
     }
   }
 
   if (mNavigator) {
     aWindowSizes->mDOMOtherSize +=
       mNavigator->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
   }
 
--- a/dom/base/test/TestCSPParser.cpp
+++ b/dom/base/test/TestCSPParser.cpp
@@ -360,17 +360,17 @@ nsresult TestPaths() {
       "report-uri http://www.example.com:8888/path_1/path_2/report.sjs&301" },
     { "report-uri /examplepath",
       "report-uri http://www.selfuri.com/examplepath" },
     { "connect-src http://www.example.com/foo%3Bsessionid=12%2C34",
       "connect-src http://www.example.com/foo;sessionid=12,34" },
     { "connect-src http://www.example.com/foo%3bsessionid=12%2c34",
       "connect-src http://www.example.com/foo;sessionid=12,34" },
     { "connect-src http://test.com/pathIncludingAz19-._~!$&'()*+=:@",
-      "connect-src http://test.com/pathincludingaz19-._~!$&'()*+=:@" },
+      "connect-src http://test.com/pathIncludingAz19-._~!$&'()*+=:@" },
     { "script-src http://www.example.com:88/.js",
       "script-src http://www.example.com:88/.js" },
     { "script-src https://foo.com/_abc/abc_/_/_a_b_c_",
       "script-src https://foo.com/_abc/abc_/_/_a_b_c_" }
   };
 
   uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
   return runTestSuite(policies, policyCount, 1);
--- a/dom/base/test/csp/test_csp_path_matching.html
+++ b/dom/base/test/csp/test_csp_path_matching.html
@@ -57,16 +57,22 @@ var policies = [
 
   ["blocked", "test1.example.com/tests"],
   ["blocked", "test1.example.com/tests/dom/base/test/csp"],
   ["blocked", "test1.example.com/tests/dom/base/test/csp/file_csp_path_matching.py"],
 
   ["blocked", "test1.example.com:8888/tests"],
   ["blocked", "test1.example.com:8888/tests/dom/base/test/csp"],
   ["blocked", "test1.example.com:8888/tests/dom/base/test/csp/file_csp_path_matching.py"],
+
+  // case insensitive matching for scheme and host, but case sensitive matching for paths
+  ["allowed", "HTTP://test1.EXAMPLE.com/tests/"],
+  ["allowed", "test1.EXAMPLE.com/tests/"],
+  ["blocked", "test1.example.com/tests/dom/base/test/CSP/?foo=val"],
+  ["blocked", "test1.example.com/tests/dom/base/test/csp/FILE_csp_path_matching.js?foo=val"],
 ]
 
 var counter = 0;
 var policy;
 
 function loadNextTest() {
   if (counter == policies.length) {
     SimpleTest.finish();
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -456,17 +456,17 @@ GetWrapperCache(void* p)
 // GetWrappeCache(void*) and GetWrapperCache(const ParentObject&).
 template <template <typename> class SmartPtr, typename T>
 inline nsWrapperCache*
 GetWrapperCache(const SmartPtr<T>& aObject)
 {
   return GetWrapperCache(aObject.get());
 }
 
-struct ParentObject {
+struct MOZ_STACK_CLASS ParentObject {
   template<class T>
   ParentObject(T* aObject) :
     mObject(aObject),
     mWrapperCache(GetWrapperCache(aObject)),
     mUseXBLScope(false)
   {}
 
   template<class T, template<typename> class SmartPtr>
@@ -477,17 +477,19 @@ struct ParentObject {
   {}
 
   ParentObject(nsISupports* aObject, nsWrapperCache* aCache) :
     mObject(aObject),
     mWrapperCache(aCache),
     mUseXBLScope(false)
   {}
 
-  nsISupports* const mObject;
+  // We don't want to make this an nsCOMPtr because of performance reasons, but
+  // it's safe because ParentObject is a stack class.
+  nsISupports* const MOZ_NON_OWNING_REF mObject;
   nsWrapperCache* const mWrapperCache;
   bool mUseXBLScope;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_BindingDeclarations_h__
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -399,16 +399,17 @@ class CGDOMJSClass(CGThing):
                       nullptr, /* defineProperty */
                       nullptr, /* defineElement */
                       nullptr, /* getGeneric  */
                       nullptr, /* getProperty */
                       nullptr, /* getElement */
                       nullptr, /* setGeneric */
                       nullptr, /* setProperty */
                       nullptr, /* setElement */
+                      nullptr, /* getOwnPropertyDescriptor */
                       nullptr, /* getGenericAttributes */
                       nullptr, /* setGenericAttributes */
                       nullptr, /* deleteGeneric */
                       nullptr, /* watch */
                       nullptr, /* unwatch */
                       nullptr, /* getElements */
                       nullptr, /* enumerate */
                       JS_ObjectToOuterObject /* thisObject */
--- a/dom/bluetooth/BluetoothInterface.cpp
+++ b/dom/bluetooth/BluetoothInterface.cpp
@@ -99,17 +99,17 @@ BluetoothInterface::GetInstance()
    * are ordered by preference.
    */
 #ifdef MOZ_B2G_BT_DAEMON
   static const char sDefaultBackend[] = "bluetoothd";
 #else
 #ifdef MOZ_B2G_BT_BLUEDROID
   static const char sDefaultBackend[] = "bluedroid";
 #else
-  static const char const * sDefaultBackend = nullptr;
+  static const char* const sDefaultBackend = nullptr;
 #endif
 #endif
 
   /* Here's where we decide which implementation to use. Currently
    * there is only Bluedroid and the Bluetooth daemon, but others are
    * possible. Having multiple interfaces built-in and selecting the
    * correct one at runtime is also an option.
    */
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -182,17 +182,17 @@ public:
   PostMessageRunnable(BroadcastChannelChild* aActor,
                       BroadcastChannelMessage* aData)
     : mActor(aActor)
     , mData(aData)
   {
     MOZ_ASSERT(mActor);
   }
 
-  NS_IMETHODIMP Run()
+  NS_IMETHODIMP Run() MOZ_OVERRIDE
   {
     MOZ_ASSERT(mActor);
     if (mActor->IsActorDestroyed()) {
       return NS_OK;
     }
 
     ClonedMessageData message;
 
@@ -216,17 +216,17 @@ public:
         message.blobsChild().AppendElement(blobChild);
       }
     }
 
     mActor->SendPostMessage(message);
     return NS_OK;
   }
 
-  NS_IMETHODIMP Cancel()
+  NS_IMETHODIMP Cancel() MOZ_OVERRIDE
   {
     mActor = nullptr;
     return NS_OK;
   }
 
 private:
   ~PostMessageRunnable() {}
 
@@ -242,23 +242,23 @@ public:
   NS_DECL_ISUPPORTS
 
   explicit CloseRunnable(BroadcastChannel* aBC)
     : mBC(aBC)
   {
     MOZ_ASSERT(mBC);
   }
 
-  NS_IMETHODIMP Run()
+  NS_IMETHODIMP Run() MOZ_OVERRIDE
   {
     mBC->Shutdown();
     return NS_OK;
   }
 
-  NS_IMETHODIMP Cancel()
+  NS_IMETHODIMP Cancel() MOZ_OVERRIDE
   {
     mBC = nullptr;
     return NS_OK;
   }
 
 private:
   ~CloseRunnable() {}
 
@@ -273,26 +273,26 @@ public:
   NS_DECL_ISUPPORTS
 
   explicit TeardownRunnable(BroadcastChannelChild* aActor)
     : mActor(aActor)
   {
     MOZ_ASSERT(mActor);
   }
 
-  NS_IMETHODIMP Run()
+  NS_IMETHODIMP Run() MOZ_OVERRIDE
   {
     MOZ_ASSERT(mActor);
     if (!mActor->IsActorDestroyed()) {
       mActor->SendClose();
     }
     return NS_OK;
   }
 
-  NS_IMETHODIMP Cancel()
+  NS_IMETHODIMP Cancel() MOZ_OVERRIDE
   {
     mActor = nullptr;
     return NS_OK;
   }
 
 private:
   ~TeardownRunnable() {}
 
--- a/dom/broadcastchannel/BroadcastChannelChild.h
+++ b/dom/broadcastchannel/BroadcastChannelChild.h
@@ -37,17 +37,17 @@ public:
   }
 
 private:
   BroadcastChannelChild(const nsAString& aOrigin,
                         const nsAString& aChannel);
 
   ~BroadcastChannelChild();
 
-  void ActorDestroy(ActorDestroyReason aWhy);
+  virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   // This raw pointer is actually the parent object.
   // It's set to null when the parent object is deleted.
   BroadcastChannel* mBC;
 
   nsString mOrigin;
   nsString mChannel;
 
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -829,16 +829,45 @@ BrowserElementParent.prototype = {
       throw Components.Exception("Invalid argument",
                                  Cr.NS_ERROR_INVALID_ARG);
     }
 
     return this._sendDOMRequest('set-input-method-active',
                                 {isActive: isActive});
   },
 
+  setNFCFocus: function(isFocus) {
+    if (!this._isAlive()) {
+      throw Components.Exception("Dead content process",
+                                 Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
+    }
+
+    // For now, we use tab id as an identifier to let NFC module know
+    // which app is in foreground. But this approach will not work in
+    // in-process mode because tab id doesn't exist. Fix bug 1116449
+    // if we are going to support in-process mode.
+    try {
+      var tabId = this._frameLoader.QueryInterface(Ci.nsIFrameLoader)
+                                   .tabParent
+                                   .tabId;
+    } catch(e) {
+      debug("SetNFCFocus for in-process mode is not yet supported");
+      throw Components.Exception("SetNFCFocus for in-process mode is not yet supported",
+                                 Cr.NS_ERROR_NOT_IMPLEMENTED);
+    }
+
+    try {
+      let nfcContentHelper =
+        Cc["@mozilla.org/nfc/content-helper;1"].getService(Ci.nsINfcBrowserAPI);
+      nfcContentHelper.setFocusApp(tabId, isFocus);
+    } catch(e) {
+      // Not all platforms support NFC
+    }
+  },
+
   /**
    * Called when the visibility of the window which owns this iframe changes.
    */
   _ownerVisibilityChange: function() {
     this._sendAsyncMsg('owner-visibility-change',
                        {visible: !this._window.document.hidden});
   },
 
--- a/dom/browser-element/nsIBrowserElementAPI.idl
+++ b/dom/browser-element/nsIBrowserElementAPI.idl
@@ -21,17 +21,17 @@ interface nsIBrowserElementNextPaintList
     { 0x651db7e3, 0x1734, 0x4536,                               \
       { 0xb1, 0x5a, 0x5b, 0x3a, 0xe6, 0x44, 0x13, 0x4c } }
 %}
 
 /**
  * Interface to the BrowserElementParent implementation. All methods
  * but setFrameLoader throw when the remote process is dead.
  */
-[scriptable, uuid(abae4fb1-7d6f-4e3f-b435-6501f1d4c659)]
+[scriptable, uuid(3811446f-90bb-42c1-b2b6-aae3603b61e1)]
 interface nsIBrowserElementAPI : nsISupports
 {
   void setFrameLoader(in nsIFrameLoader frameLoader);
 
   void setVisible(in boolean visible);
   nsIDOMDOMRequest getVisible();
   void setActive(in boolean active);
   boolean getActive();
@@ -66,9 +66,11 @@ interface nsIBrowserElementAPI : nsISupp
   nsIDOMDOMRequest getCanGoBack();
   nsIDOMDOMRequest getCanGoForward();
   nsIDOMDOMRequest getContentDimensions();
 
   void addNextPaintListener(in nsIBrowserElementNextPaintListener listener);
   void removeNextPaintListener(in nsIBrowserElementNextPaintListener listener);
 
   nsIDOMDOMRequest setInputMethodActive(in boolean isActive);
+
+  void setNFCFocus(in boolean isFocus);
 };
--- a/dom/camera/CameraPreferences.cpp
+++ b/dom/camera/CameraPreferences.cpp
@@ -32,29 +32,27 @@ uint32_t CameraPreferences::sPrefCameraC
 bool CameraPreferences::sPrefCameraParametersIsLowMemory = false;
 
 #ifdef MOZ_WIDGET_GONK
 StaticRefPtr<CameraPreferences> CameraPreferences::sObserver;
 
 NS_IMPL_ISUPPORTS(CameraPreferences, nsIObserver);
 #endif
 
-#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
 /* static */
 nsresult
 CameraPreferences::UpdatePref(const char* aPref, nsresult& aVal)
 {
   uint32_t val;
   nsresult rv = Preferences::GetUint(aPref, &val);
   if (NS_SUCCEEDED(rv)) {
     aVal = static_cast<nsresult>(val);
   }
   return rv;
 }
-#endif
 
 /* static */
 nsresult
 CameraPreferences::UpdatePref(const char* aPref, uint32_t& aVal)
 {
   uint32_t val;
   nsresult rv = Preferences::GetUint(aPref, &val);
   if (NS_SUCCEEDED(rv)) {
@@ -151,26 +149,24 @@ CameraPreferences::PreferenceChanged(con
     DOM_CAMERA_LOGE("Preference '%s' is not tracked by CameraPreferences\n", aPref);
     return;
   }
 
   Pref& p = sPrefs[i];
   nsresult rv;
   switch (p.mValueType) {
     case kPrefValueIsNsResult:
-    #ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
       {
         nsresult& v = *p.mValue.mAsNsResult;
         rv = UpdatePref(aPref, v);
         if (NS_SUCCEEDED(rv)) {
           DOM_CAMERA_LOGI("Preference '%s' has changed, 0x%x\n", aPref, v);
         }
       }
       break;
-    #endif
 
     case kPrefValueIsUint32:
       {
         uint32_t& v = *p.mValue.mAsUint32;
         rv = UpdatePref(aPref, v);
         if (NS_SUCCEEDED(rv)) {
           DOM_CAMERA_LOGI("Preference '%s' has changed, %u\n", aPref, v);
         }
@@ -326,17 +322,16 @@ CameraPreferences::GetPref(const char* a
     return false;
   }
 
   DOM_CAMERA_LOGI("Preference '%s', got '%s'\n", aPref, (*s)->get());
   aVal = **s;
   return true;
 }
 
-#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
 /* static */
 bool
 CameraPreferences::GetPref(const char* aPref, nsresult& aVal)
 {
   MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
   MonitorAutoLock mon(*sPrefMonitor);
 
   uint32_t i = PrefToIndex(aPref);
@@ -354,17 +349,16 @@ CameraPreferences::GetPref(const char* a
     DOM_CAMERA_LOGW("Preference '%s' is not set\n", aPref);
     return false;
   }
 
   DOM_CAMERA_LOGI("Preference '%s', got 0x%x\n", aPref, v);
   aVal = v;
   return true;
 }
-#endif
 
 /* static */
 bool
 CameraPreferences::GetPref(const char* aPref, uint32_t& aVal)
 {
   MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
   MonitorAutoLock mon(*sPrefMonitor);
 
--- a/dom/camera/CameraPreferences.h
+++ b/dom/camera/CameraPreferences.h
@@ -7,23 +7,16 @@
 #define DOM_CAMERA_CAMERAPREFERENCES_H
 
 #include "nsString.h"
 #include "nsIObserver.h"
 #ifdef MOZ_WIDGET_GONK
 #include "mozilla/StaticPtr.h"
 #endif
 
-#if defined(MOZ_HAVE_CXX11_STRONG_ENUMS) || defined(MOZ_HAVE_CXX11_ENUM_TYPE)
-// Older compilers that don't support strongly-typed enums
-// just typedef uint32_t to nsresult, which results in conflicting
-// overloaded members in CameraPreferences.
-#define CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
-#endif
-
 namespace mozilla {
 
 template<class T> class StaticAutoPtr;
 
 class CameraPreferences
 #ifdef MOZ_WIDGET_GONK
   : public nsIObserver
 #endif
@@ -33,30 +26,26 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 #endif
 
   static bool Initialize();
   static void Shutdown();
 
   static bool GetPref(const char* aPref, nsACString& aVal);
-#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
   static bool GetPref(const char* aPref, nsresult& aVal);
-#endif
   static bool GetPref(const char* aPref, uint32_t& aVal);
   static bool GetPref(const char* aPref, bool& aVal);
 
 protected:
   static const uint32_t kPrefNotFound = UINT32_MAX;
   static uint32_t PrefToIndex(const char* aPref);
 
   static void PreferenceChanged(const char* aPref, void* aClosure);
-#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
   static nsresult UpdatePref(const char* aPref, nsresult& aVar);
-#endif
   static nsresult UpdatePref(const char* aPref, uint32_t& aVar);
   static nsresult UpdatePref(const char* aPref, nsACString& aVar);
   static nsresult UpdatePref(const char* aPref, bool& aVar);
 
   enum PrefValueType {
     kPrefValueIsNsResult,
     kPrefValueIsUint32,
     kPrefValueIsCString,
--- a/dom/camera/CameraPreviewMediaStream.h
+++ b/dom/camera/CameraPreviewMediaStream.h
@@ -37,16 +37,17 @@ protected:
  */
 class CameraPreviewMediaStream : public MediaStream
 {
   typedef mozilla::layers::Image Image;
 
 public:
   explicit CameraPreviewMediaStream(DOMMediaStream* aWrapper);
 
+  virtual CameraPreviewMediaStream* AsCameraPreviewStream() MOZ_OVERRIDE { return this; };
   virtual void AddAudioOutput(void* aKey) MOZ_OVERRIDE;
   virtual void SetAudioOutputVolume(void* aKey, float aVolume) MOZ_OVERRIDE;
   virtual void RemoveAudioOutput(void* aKey) MOZ_OVERRIDE;
   virtual void AddVideoOutput(VideoFrameContainer* aContainer) MOZ_OVERRIDE;
   virtual void RemoveVideoOutput(VideoFrameContainer* aContainer) MOZ_OVERRIDE;
   virtual void ChangeExplicitBlockerCount(int32_t aDelta) MOZ_OVERRIDE;
   virtual void AddListener(MediaStreamListener* aListener) MOZ_OVERRIDE;
   virtual void RemoveListener(MediaStreamListener* aListener) MOZ_OVERRIDE;
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -2990,55 +2990,46 @@ CanvasRenderingContext2D::SetFont(const 
   nsRefPtr<nsStyleContext> sc =
     GetFontStyleContext(mCanvasElement, font, presShell, usedFont, error);
   if (!sc) {
     return;
   }
 
   const nsStyleFont* fontStyle = sc->StyleFont();
 
-  nsIAtom* language = fontStyle->mLanguage;
-  if (!language) {
-    language = presShell->GetPresContext()->GetLanguageFromCharset();
-  }
-
-  // use CSS pixels instead of dev pixels to avoid being affected by page zoom
-  const uint32_t aupcp = nsPresContext::AppUnitsPerCSSPixel();
-
-  bool printerFont = (presShell->GetPresContext()->Type() == nsPresContext::eContext_PrintPreview ||
-                      presShell->GetPresContext()->Type() == nsPresContext::eContext_Print);
+  nsPresContext *c = presShell->GetPresContext();
 
   // Purposely ignore the font size that respects the user's minimum
   // font preference (fontStyle->mFont.size) in favor of the computed
   // size (fontStyle->mSize).  See
   // https://bugzilla.mozilla.org/show_bug.cgi?id=698652.
   MOZ_ASSERT(!fontStyle->mAllowZoom,
              "expected text zoom to be disabled on this nsStyleFont");
-  gfxFontStyle style(fontStyle->mFont.style,
-                     fontStyle->mFont.weight,
-                     fontStyle->mFont.stretch,
-                     NSAppUnitsToFloatPixels(fontStyle->mSize, float(aupcp)),
-                     language,
-                     fontStyle->mExplicitLanguage,
-                     fontStyle->mFont.sizeAdjust,
-                     fontStyle->mFont.systemFont,
-                     printerFont,
-                     fontStyle->mFont.synthesis & NS_FONT_SYNTHESIS_WEIGHT,
-                     fontStyle->mFont.synthesis & NS_FONT_SYNTHESIS_STYLE,
-                     fontStyle->mFont.languageOverride);
-
-  fontStyle->mFont.AddFontFeaturesToStyle(&style);
-
-  nsPresContext *c = presShell->GetPresContext();
-  CurrentState().fontGroup =
-      gfxPlatform::GetPlatform()->CreateFontGroup(fontStyle->mFont.fontlist,
-                                                  &style,
-                                                  c->GetUserFontSet());
+  nsFont resizedFont(fontStyle->mFont);
+  // Create a font group working in units of CSS pixels instead of the usual
+  // device pixels, to avoid being affected by page zoom. nsFontMetrics will
+  // convert nsFont size in app units to device pixels for the font group, so
+  // here we first apply to the size the equivalent of a conversion from device
+  // pixels to CSS pixels, to adjust for the difference in expectations from
+  // other nsFontMetrics clients.
+  resizedFont.size =
+    (fontStyle->mSize * c->AppUnitsPerDevPixel()) / c->AppUnitsPerCSSPixel();
+
+  nsRefPtr<nsFontMetrics> metrics;
+  c->DeviceContext()->GetMetricsFor(resizedFont,
+                                    fontStyle->mLanguage,
+                                    fontStyle->mExplicitLanguage,
+                                    gfxFont::eHorizontal,
+                                    c->GetUserFontSet(),
+                                    c->GetTextPerfMetrics(),
+                                    *getter_AddRefs(metrics));
+
+  gfxFontGroup* newFontGroup = metrics->GetThebesFontGroup();
+  CurrentState().fontGroup = newFontGroup;
   NS_ASSERTION(CurrentState().fontGroup, "Could not get font group");
-  CurrentState().fontGroup->SetTextPerfMetrics(c->GetTextPerfMetrics());
   CurrentState().font = usedFont;
   CurrentState().fontFont = fontStyle->mFont;
   CurrentState().fontFont.size = fontStyle->mSize;
   CurrentState().fontLanguage = fontStyle->mLanguage;
   CurrentState().fontExplicitLanguage = fontStyle->mExplicitLanguage;
 }
 
 void
--- a/dom/contacts/ContactManager.js
+++ b/dom/contacts/ContactManager.js
@@ -85,19 +85,22 @@ ContactManager.prototype = {
     this.__DOM_IMPL__.setEventHandler("oncontactchange", aHandler);
   },
 
   get oncontactchange() {
     return this.__DOM_IMPL__.getEventHandler("oncontactchange");
   },
 
   _convertContact: function(aContact) {
-    let contact = Cu.cloneInto(aContact, this._window);
-    let newContact = new this._window.mozContact(contact.properties);
-    newContact.setMetadata(contact.id, contact.published, contact.updated);
+    let properties = aContact.properties;
+    if (properties.photo && properties.photo.length) {
+      properties.photo = Cu.cloneInto(properties.photo, this._window);
+    }
+    let newContact = new this._window.mozContact(aContact.properties);
+    newContact.setMetadata(aContact.id, aContact.published, aContact.updated);
     return newContact;
   },
 
   _convertContacts: function(aContacts) {
     let contacts = new this._window.Array();
     for (let i in aContacts) {
       contacts.push(this._convertContact(aContacts[i]));
     }
--- a/dom/events/EventListenerManager.h
+++ b/dom/events/EventListenerManager.h
@@ -157,17 +157,17 @@ class EventListenerManager MOZ_FINAL
 public:
   struct Listener
   {
     EventListenerHolder mListener;
     nsCOMPtr<nsIAtom> mTypeAtom; // for the main thread
     nsString mTypeString; // for non-main-threads
     uint16_t mEventType;
 
-    enum ListenerType MOZ_ENUM_TYPE(uint8_t)
+    enum ListenerType : uint8_t
     {
       eNativeListener = 0,
       eJSEventListener,
       eWrappedJSListener,
       eWebIDLListener,
       eListenerTypeCount
     };
     uint8_t mListenerType;
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -453,16 +453,20 @@ ERROR_EVENT(error,
 FORWARDED_EVENT(focus,
                 NS_FOCUS_CONTENT,
                 EventNameType_HTMLXUL,
                 eFocusEventClass)
 FORWARDED_EVENT(load,
                 NS_LOAD,
                 EventNameType_All,
                 eBasicEventClass)
+FORWARDED_EVENT(resize,
+                NS_RESIZE_EVENT,
+                EventNameType_All,
+                eBasicEventClass)
 FORWARDED_EVENT(scroll,
                 NS_SCROLL_EVENT,
                 (EventNameType_HTMLXUL | EventNameType_SVGSVG),
                 eBasicEventClass)
 
 WINDOW_EVENT(afterprint,
              NS_AFTERPRINT,
              EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
@@ -507,21 +511,16 @@ WINDOW_EVENT(pageshow,
              EventNameType_HTMLBodyOrFramesetOnly,
              eBasicEventClass)
 WINDOW_EVENT(popstate,
              NS_POPSTATE,
              EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
              eBasicEventClass)
 // Not supported yet
 // WINDOW_EVENT(redo)
-WINDOW_EVENT(resize,
-             NS_RESIZE_EVENT,
-             (EventNameType_XUL | EventNameType_SVGSVG |
-              EventNameType_HTMLBodyOrFramesetOnly),
-             eBasicEventClass)
 // Not supported yet
 // WINDOW_EVENT(storage)
 // Not supported yet
 // WINDOW_EVENT(undo)
 WINDOW_EVENT(unload,
              NS_PAGE_UNLOAD,
              (EventNameType_XUL | EventNameType_SVGSVG |
               EventNameType_HTMLBodyOrFramesetOnly),
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -424,17 +424,17 @@ protected:
      * prefs, the overflowDelta values would be inflated.
      * CancelApplyingUserPrefsFromOverflowDelta() cancels the inflation.
      */
     void CancelApplyingUserPrefsFromOverflowDelta(WidgetWheelEvent* aEvent);
 
     /**
      * Computes the default action for the aEvent with the prefs.
      */
-    enum Action MOZ_ENUM_TYPE(uint8_t)
+    enum Action : uint8_t
     {
       ACTION_NONE = 0,
       ACTION_SCROLL,
       ACTION_HISTORY,
       ACTION_ZOOM,
       ACTION_LAST = ACTION_ZOOM
     };
     Action ComputeActionFor(WidgetWheelEvent* aEvent);
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/dom/HTMLFormElement.h"
+#include "mozilla/dom/TabParent.h"
 
 #include "HTMLInputElement.h"
 #include "IMEContentObserver.h"
 
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
@@ -383,16 +384,37 @@ IMEStateManager::OnChangeFocusInternal(n
   if (NS_WARN_IF(!widget)) {
     PR_LOG(sISMLog, PR_LOG_ERROR,
       ("ISM:   IMEStateManager::OnChangeFocusInternal(), FAILED due to "
        "no widget to manage its IME state"));
     return NS_OK;
   }
 
   IMEState newState = GetNewIMEState(aPresContext, aContent);
+
+  // In e10s, remote content may have IME focus.  The main process (i.e. this process)
+  // would attempt to set state to DISABLED if, for example, the user clicks
+  // some other remote content.  The content process would later re-ENABLE IME, meaning
+  // that all state-changes were unnecessary.
+  // Here we filter the common case where the main process knows that the remote
+  // process controls IME focus.  The DISABLED->re-ENABLED progression can
+  // still happen since remote content may be concurrently communicating its claim
+  // on focus to the main process... but this cannot cause bugs like missed keypresses.
+  // (It just means a lot of needless IPC.)
+  if ((newState.mEnabled == IMEState::DISABLED) && TabParent::GetIMETabParent()) {
+    PR_LOG(sISMLog, PR_LOG_DEBUG,
+      ("ISM:   IMEStateManager::OnChangeFocusInternal(), "
+       "Parent process cancels to set DISABLED state because the content process "
+       "has IME focus and has already sets IME state"));  
+    MOZ_ASSERT(XRE_IsParentProcess(),
+      "TabParent::GetIMETabParent() should never return non-null value "
+      "in the content process");
+    return NS_OK;
+  }
+
   if (!focusActuallyChanging) {
     // actual focus isn't changing, but if IME enabled state is changing,
     // we should do it.
     InputContext context = widget->GetInputContext();
     if (context.mIMEState.mEnabled == newState.mEnabled) {
       PR_LOG(sISMLog, PR_LOG_DEBUG,
         ("ISM:   IMEStateManager::OnChangeFocusInternal(), "
          "neither focus nor IME state is changing"));
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -522,24 +522,24 @@ HTMLMediaElement::GetMozSrcObject() cons
                "MediaStream should have been set up properly");
   nsRefPtr<DOMMediaStream> stream = mSrcAttrStream;
   return stream.forget();
 }
 
 void
 HTMLMediaElement::SetMozSrcObject(DOMMediaStream& aValue)
 {
-  mSrcAttrStream = &aValue;
-  Load();
+  SetMozSrcObject(&aValue);
 }
 
 void
 HTMLMediaElement::SetMozSrcObject(DOMMediaStream* aValue)
 {
-  SetMozSrcObject(*aValue);
+  mSrcAttrStream = aValue;
+  Load();
 }
 
 /* readonly attribute nsIDOMHTMLMediaElement mozAutoplayEnabled; */
 NS_IMETHODIMP HTMLMediaElement::GetMozAutoplayEnabled(bool *aAutoplayEnabled)
 {
   *aAutoplayEnabled = mAutoplayEnabled;
 
   return NS_OK;
@@ -2519,41 +2519,41 @@ nsresult HTMLMediaElement::BindToTree(ns
   if (aDocument) {
     mAutoplayEnabled =
       IsAutoplayEnabled() && (!aDocument || !aDocument->IsStaticDocument()) &&
       !IsEditable();
     // The preload action depends on the value of the autoplay attribute.
     // It's value may have changed, so update it.
     UpdatePreloadAction();
   }
+  mElementInTreeState = ELEMENT_INTREE;
+
   if (mDecoder) {
     // When the MediaElement is binding to tree, the dormant status is
     // aligned to document's hidden status.
-    nsIDocument* ownerDoc = OwnerDoc();
-    if (ownerDoc) {
-      mDecoder->SetDormantIfNecessary(ownerDoc->Hidden());
-    }
-  }
-  mElementInTreeState = ELEMENT_INTREE;
+    mDecoder->NotifyOwnerActivityChanged();
+  }
 
   return rv;
 }
 
 void HTMLMediaElement::UnbindFromTree(bool aDeep,
                                       bool aNullParent)
 {
   if (!mPaused && mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY)
     Pause();
 
-  if (mDecoder) {
-    mDecoder->SetDormantIfNecessary(true);
-  }
   mElementInTreeState = ELEMENT_NOT_INTREE_HAD_INTREE;
 
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
+
+  if (mDecoder) {
+    MOZ_ASSERT(IsHidden());
+    mDecoder->NotifyOwnerActivityChanged();
+  }
 }
 
 /* static */
 CanPlayStatus
 HTMLMediaElement::GetCanPlay(const nsAString& aType)
 {
   nsContentTypeParser parser(aType);
   nsAutoString mimeType;
@@ -2888,29 +2888,32 @@ void HTMLMediaElement::SetupSrcMediaStre
 
   mSrcStream = aStream;
 
   nsIDOMWindow* window = OwnerDoc()->GetInnerWindow();
   if (!window) {
     return;
   }
 
-  // Now that we have access to |mSrcStream| we can pipe it to our shadow
-  // version |mPlaybackStream|. If two media elements are playing the
-  // same realtime DOMMediaStream, this allows them to pause playback
-  // independently of each other.
-  mPlaybackStream = DOMMediaStream::CreateTrackUnionStream(window);
-  mPlaybackStreamInputPort = mPlaybackStream->GetStream()->AsProcessedStream()->
-    AllocateInputPort(mSrcStream->GetStream(), MediaInputPort::FLAG_BLOCK_OUTPUT);
-
-  nsRefPtr<nsIPrincipal> principal = GetCurrentPrincipal();
-  mPlaybackStream->CombineWithPrincipal(principal);
-
-  // Let |mSrcStream| decide when the stream has finished.
-  GetSrcMediaStream()->AsProcessedStream()->SetAutofinish(true);
+  // XXX Remove this if with CameraPreviewMediaStream per bug 1124630.
+  if (!mSrcStream->GetStream()->AsCameraPreviewStream()) {
+    // Now that we have access to |mSrcStream| we can pipe it to our shadow
+    // version |mPlaybackStream|. If two media elements are playing the
+    // same realtime DOMMediaStream, this allows them to pause playback
+    // independently of each other.
+    mPlaybackStream = DOMMediaStream::CreateTrackUnionStream(window);
+    mPlaybackStreamInputPort = mPlaybackStream->GetStream()->AsProcessedStream()->
+      AllocateInputPort(mSrcStream->GetStream(), MediaInputPort::FLAG_BLOCK_OUTPUT);
+
+    nsRefPtr<nsIPrincipal> principal = GetCurrentPrincipal();
+    mPlaybackStream->CombineWithPrincipal(principal);
+
+    // Let |mSrcStream| decide when the stream has finished.
+    GetSrcMediaStream()->AsProcessedStream()->SetAutofinish(true);
+  }
 
   nsRefPtr<MediaStream> stream = mSrcStream->GetStream();
   if (stream) {
     stream->SetAudioChannelType(mAudioChannel);
   }
 
   // XXX if we ever support capturing the output of a media element which is
   // playing a stream, we'll need to add a CombineWithPrincipal call here.
@@ -2948,17 +2951,19 @@ void HTMLMediaElement::SetupSrcMediaStre
 void HTMLMediaElement::EndSrcMediaStreamPlayback()
 {
   MediaStream* stream = GetSrcMediaStream();
   if (stream) {
     stream->RemoveListener(mSrcStreamListener);
   }
   mSrcStream->DisconnectTrackListListeners(AudioTracks(), VideoTracks());
 
-  mPlaybackStreamInputPort->Destroy();
+  if (mPlaybackStreamInputPort) {
+    mPlaybackStreamInputPort->Destroy();
+  }
 
   // Kill its reference to this element
   mSrcStreamListener->Forget();
   mSrcStreamListener = nullptr;
   if (stream) {
     stream->RemoveAudioOutput(this);
   }
   VideoFrameContainer* container = GetVideoFrameContainer();
@@ -2997,16 +3002,20 @@ void HTMLMediaElement::MetadataLoaded(co
                                       nsAutoPtr<const MetadataTags> aTags)
 {
   mHasAudio = aInfo->HasAudio();
   mHasVideo = aInfo->HasVideo();
   mTags = aTags.forget();
   mLoadedDataFired = false;
   ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
   DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
+  if (IsVideo() && mHasVideo) {
+    mMediaSize = aInfo->mVideo.mDisplay;
+    DispatchAsyncEvent(NS_LITERAL_STRING("resize"));
+  }
   DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
   if (mDecoder && mDecoder->IsTransportSeekable() && mDecoder->IsMediaSeekable()) {
     ProcessMediaFragmentURI();
     mDecoder->SetFragmentEndTime(mFragmentEnd);
   }
 
   // Tracks just got known, pass the info along to the output streams
   uint8_t hints = (mHasAudio ? DOMMediaStream::HINT_CONTENTS_AUDIO : 0) |
@@ -3514,16 +3523,31 @@ void HTMLMediaElement::CheckAutoplayData
     } else if (mSrcStream) {
       SetPlayedOrSeeked(true);
       GetSrcMediaStream()->ChangeExplicitBlockerCount(-1);
     }
     DispatchAsyncEvent(NS_LITERAL_STRING("play"));
   }
 }
 
+bool HTMLMediaElement::IsActive()
+{
+  nsIDocument* ownerDoc = OwnerDoc();
+  return ownerDoc && ownerDoc->IsActive() && ownerDoc->IsVisible();
+}
+
+bool HTMLMediaElement::IsHidden()
+{
+  if (mElementInTreeState == ELEMENT_NOT_INTREE_HAD_INTREE) {
+    return true;
+  }
+  nsIDocument* ownerDoc = OwnerDoc();
+  return !ownerDoc || ownerDoc->Hidden();
+}
+
 VideoFrameContainer* HTMLMediaElement::GetVideoFrameContainer()
 {
   if (mVideoFrameContainer)
     return mVideoFrameContainer;
 
   // Only video frames need an image container.
   if (!IsVideo()) {
     return nullptr;
@@ -3637,16 +3661,20 @@ void HTMLMediaElement::NotifyDecoderPrin
   if (mMediaKeys && NS_FAILED(mMediaKeys->CheckPrincipals())) {
     mMediaKeys->Shutdown();
   }
 #endif
 }
 
 void HTMLMediaElement::UpdateMediaSize(nsIntSize size)
 {
+  if (IsVideo() && mReadyState != HAVE_NOTHING && mMediaSize != size) {
+    DispatchAsyncEvent(NS_LITERAL_STRING("resize"));
+  }
+
   mMediaSize = size;
   UpdateReadyStateForData(mLastNextFrameStatus);
 }
 
 void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendEvents)
 {
   if (aPauseElement != mPausedForInactiveDocumentOrChannel) {
     mPausedForInactiveDocumentOrChannel = aPauseElement;
@@ -3693,38 +3721,29 @@ void HTMLMediaElement::SuspendOrResumeEl
 }
 
 void HTMLMediaElement::NotifyOwnerDocumentActivityChanged()
 {
   nsIDocument* ownerDoc = OwnerDoc();
 
   if (mDecoder) {
     mDecoder->SetElementVisibility(!ownerDoc->Hidden());
-
-    if (mElementInTreeState == ELEMENT_NOT_INTREE_HAD_INTREE) {
-      mDecoder->SetDormantIfNecessary(true);
-    } else if (mElementInTreeState == ELEMENT_NOT_INTREE ||
-               mElementInTreeState == ELEMENT_INTREE) {
-      // The MediaElement had never been binded to tree, or in the tree now,
-      // align to document.
-      mDecoder->SetDormantIfNecessary(ownerDoc->Hidden());
-    }
+    mDecoder->NotifyOwnerActivityChanged();
   }
 
   // SetVisibilityState will update mMuted with MUTED_BY_AUDIO_CHANNEL via the
   // CanPlayChanged callback.
   if (UseAudioChannelService() && mPlayingThroughTheAudioChannel &&
       mAudioChannelAgent) {
     AutoNoJSAPI nojsapi;
     mAudioChannelAgent->SetVisibilityState(!ownerDoc->Hidden());
   }
-  bool suspendEvents = !ownerDoc->IsActive() || !ownerDoc->IsVisible();
-  bool pauseElement = suspendEvents || (mMuted & MUTED_BY_AUDIO_CHANNEL);
-
-  SuspendOrResumeElement(pauseElement, suspendEvents);
+  bool pauseElement = !IsActive() || (mMuted & MUTED_BY_AUDIO_CHANNEL);
+
+  SuspendOrResumeElement(pauseElement, !IsActive());
 
   AddRemoveSelfReference();
 }
 
 void HTMLMediaElement::AddRemoveSelfReference()
 {
   // XXX we could release earlier here in many situations if we examined
   // which event listeners are attached. Right now we assume there is a
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -206,16 +206,20 @@ public:
 
   // Called to indicate the download is progressing.
   virtual void DownloadProgressed() MOZ_FINAL MOZ_OVERRIDE;
 
   // Called by the media decoder to indicate whether the media cache has
   // suspended the channel.
   virtual void NotifySuspendedByCache(bool aIsSuspended) MOZ_FINAL MOZ_OVERRIDE;
 
+  virtual bool IsActive() MOZ_FINAL MOZ_OVERRIDE;
+
+  virtual bool IsHidden() MOZ_FINAL MOZ_OVERRIDE;
+
   // Called by the media decoder and the video frame to get the
   // ImageContainer containing the video data.
   virtual VideoFrameContainer* GetVideoFrameContainer() MOZ_FINAL MOZ_OVERRIDE;
   layers::ImageContainer* GetImageContainer();
 
   // Dispatch events
   virtual nsresult DispatchAsyncEvent(const nsAString& aName) MOZ_FINAL MOZ_OVERRIDE;
 
@@ -331,17 +335,21 @@ public:
    * be fired if we've not fired a timeupdate event (for any reason) in the
    * last 250ms, as required by the spec when the current time is periodically
    * increasing during playback.
    */
   virtual void FireTimeUpdate(bool aPeriodic) MOZ_FINAL MOZ_OVERRIDE;
 
   MediaStream* GetSrcMediaStream() const
   {
-    NS_ASSERTION(mPlaybackStream, "Don't call this when not playing a stream");
+    NS_ASSERTION(mSrcStream, "Don't call this when not playing a stream");
+    if (!mPlaybackStream) {
+      // XXX Remove this check with CameraPreviewMediaStream per bug 1124630.
+      return mSrcStream->GetStream();
+    }
     return mPlaybackStream->GetStream();
   }
 
   // WebIDL
 
   MediaError* GetError() const
   {
     return mError;
@@ -369,17 +377,17 @@ public:
 
   uint16_t NetworkState() const
   {
     return mNetworkState;
   }
 
   // Called by the media decoder object, on the main thread,
   // when the connection between Rtsp server and client gets lost.
-  void ResetConnectionState() MOZ_FINAL MOZ_OVERRIDE;
+  virtual void ResetConnectionState() MOZ_FINAL MOZ_OVERRIDE;
 
   // XPCOM GetPreload() is OK
   void SetPreload(const nsAString& aValue, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::preload, aValue, aRv);
   }
 
   already_AddRefed<TimeRanges> Buffered() const;
--- a/dom/html/nsBrowserElement.cpp
+++ b/dom/html/nsBrowserElement.cpp
@@ -537,9 +537,41 @@ nsBrowserElement::SetInputMethodActive(b
       aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     }
     return nullptr;
   }
 
   return req.forget().downcast<DOMRequest>();
 }
 
+void
+nsBrowserElement::SetNFCFocus(bool aIsFocus,
+                              ErrorResult& aRv)
+{
+  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
+
+  nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
+  if (!frameLoader) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  nsCOMPtr<nsIDOMElement> ownerElement;
+  nsresult rv = frameLoader->GetOwnerElement(getter_AddRefs(ownerElement));
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return;
+  }
+
+  nsCOMPtr<nsINode> node = do_QueryInterface(ownerElement);
+  nsCOMPtr<nsIPrincipal> principal = node->NodePrincipal();
+  if (!nsContentUtils::IsExactSitePermAllow(principal, "nfc-manager")) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+    return;
+  }
+
+  rv = mBrowserElementAPI->SetNFCFocus(aIsFocus);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  }
+}
+
 } // namespace mozilla
--- a/dom/html/nsBrowserElement.h
+++ b/dom/html/nsBrowserElement.h
@@ -84,16 +84,19 @@ public:
   void AddNextPaintListener(dom::BrowserElementNextPaintEventCallback& listener,
                             ErrorResult& aRv);
   void RemoveNextPaintListener(dom::BrowserElementNextPaintEventCallback& listener,
                                ErrorResult& aRv);
 
   already_AddRefed<dom::DOMRequest> SetInputMethodActive(bool isActive,
                                                          ErrorResult& aRv);
 
+  void SetNFCFocus(bool isFocus,
+                   ErrorResult& aRv);
+
 protected:
   NS_IMETHOD_(already_AddRefed<nsFrameLoader>) GetFrameLoader() = 0;
   nsCOMPtr<nsIBrowserElementAPI> mBrowserElementAPI;
 
 private:
   void InitBrowserElementAPI();
   bool IsBrowserElementOrThrow(ErrorResult& aRv);
   bool IsNotWidgetOrThrow(ErrorResult& aRv);
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -3934,17 +3934,16 @@ protected:
   nsTArray<MaybeBlockedDatabaseInfo> mMaybeBlockedDatabases;
 
   const CommonFactoryRequestParams mCommonParams;
   nsCString mGroup;
   nsCString mOrigin;
   nsCString mDatabaseId;
   State mState;
   bool mIsApp;
-  bool mHasUnlimStoragePerm;
   bool mEnforcingQuota;
   const bool mDeleting;
   bool mBlockedQuotaManager;
   bool mChromeWriteAccessAllowed;
 
 public:
   void
   NoteDatabaseBlocked(Database* aDatabase);
@@ -10498,17 +10497,16 @@ FactoryOp::FactoryOp(Factory* aFactory,
                      bool aDeleting)
   : DatabaseOperationBase(aFactory->GetLoggingInfo()->Id(),
                           aFactory->GetLoggingInfo()->NextRequestSN())
   , mFactory(aFactory)
   , mContentParent(Move(aContentParent))
   , mCommonParams(aCommonParams)
   , mState(State_Initial)
   , mIsApp(false)
-  , mHasUnlimStoragePerm(false)
   , mEnforcingQuota(true)
   , mDeleting(aDeleting)
   , mBlockedQuotaManager(false)
   , mChromeWriteAccessAllowed(false)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aFactory);
   MOZ_ASSERT(!QuotaClient::IsShuttingDownOnNonMainThread());
@@ -10814,25 +10812,23 @@ FactoryOp::CheckPermission(ContentParent
       }
 
       mChromeWriteAccessAllowed = canWrite;
     } else {
       mChromeWriteAccessAllowed = true;
     }
 
     if (State_Initial == mState) {
-      QuotaManager::GetInfoForChrome(&mGroup, &mOrigin, &mIsApp,
-                                     &mHasUnlimStoragePerm);
+      QuotaManager::GetInfoForChrome(&mGroup, &mOrigin, &mIsApp);
 
       MOZ_ASSERT(!QuotaManager::IsFirstPromptRequired(persistenceType, mOrigin,
                                                       mIsApp));
 
       mEnforcingQuota =
-        QuotaManager::IsQuotaEnforced(persistenceType, mOrigin, mIsApp,
-                                      mHasUnlimStoragePerm);
+        QuotaManager::IsQuotaEnforced(persistenceType, mOrigin, mIsApp);
     }
 
     *aPermission = PermissionRequestBase::kPermissionAllowed;
     return NS_OK;
   }
 
   MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
 
@@ -10841,19 +10837,17 @@ FactoryOp::CheckPermission(ContentParent
     PrincipalInfoToPrincipal(principalInfo, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsCString group;
   nsCString origin;
   bool isApp;
-  bool hasUnlimStoragePerm;
-  rv = QuotaManager::GetInfoFromPrincipal(principal, &group, &origin,
-                                          &isApp, &hasUnlimStoragePerm);
+  rv = QuotaManager::GetInfoFromPrincipal(principal, &group, &origin, &isApp);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
   if (persistenceType == PERSISTENCE_TYPE_PERSISTENT &&
       !QuotaManager::IsOriginWhitelistedForPersistentStorage(origin) &&
       !isApp) {
@@ -10888,21 +10882,19 @@ FactoryOp::CheckPermission(ContentParent
     permission = PermissionRequestBase::kPermissionAllowed;
   }
 
   if (permission != PermissionRequestBase::kPermissionDenied &&
       State_Initial == mState) {
     mGroup = group;
     mOrigin = origin;
     mIsApp = isApp;
-    mHasUnlimStoragePerm = hasUnlimStoragePerm;
 
     mEnforcingQuota =
-      QuotaManager::IsQuotaEnforced(persistenceType, mOrigin, mIsApp,
-                                    mHasUnlimStoragePerm);
+      QuotaManager::IsQuotaEnforced(persistenceType, mOrigin, mIsApp);
   }
 
   *aPermission = permission;
   return NS_OK;
 }
 
 nsresult
 FactoryOp::SendVersionChangeMessages(DatabaseActorInfo* aDatabaseActorInfo,
@@ -11284,17 +11276,16 @@ OpenDatabaseOp::DoDatabaseWork()
 
   nsCOMPtr<nsIFile> dbDirectory;
 
   nsresult rv =
     quotaManager->EnsureOriginIsInitialized(persistenceType,
                                             mGroup,
                                             mOrigin,
                                             mIsApp,
-                                            mHasUnlimStoragePerm,
                                             getter_AddRefs(dbDirectory));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = dbDirectory->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -1099,31 +1099,30 @@ IDBDatabase::GetQuotaInfo(nsACString& aO
   PrincipalInfo* principalInfo = mFactory->GetPrincipalInfo();
   MOZ_ASSERT(principalInfo);
 
   switch (principalInfo->type()) {
     case PrincipalInfo::TNullPrincipalInfo:
       MOZ_CRASH("Is this needed?!");
 
     case PrincipalInfo::TSystemPrincipalInfo:
-      QuotaManager::GetInfoForChrome(nullptr, &aOrigin, nullptr, nullptr);
+      QuotaManager::GetInfoForChrome(nullptr, &aOrigin, nullptr);
       return NS_OK;
 
     case PrincipalInfo::TContentPrincipalInfo: {
       nsresult rv;
       nsCOMPtr<nsIPrincipal> principal =
         PrincipalInfoToPrincipal(*principalInfo, &rv);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       rv = QuotaManager::GetInfoFromPrincipal(principal,
                                               nullptr,
                                               &aOrigin,
-                                              nullptr,
                                               nullptr);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
 
       return NS_OK;
     }
 
--- a/dom/indexedDB/IDBMutableFile.cpp
+++ b/dom/indexedDB/IDBMutableFile.cpp
@@ -157,17 +157,16 @@ IDBMutableFile::Create(IDBDatabase* aDat
     return nullptr;
   }
 
   nsCString group;
   nsCString origin;
   if (NS_WARN_IF(NS_FAILED(QuotaManager::GetInfoFromPrincipal(principal,
                                                               &group,
                                                               &origin,
-                                                              nullptr,
                                                               nullptr)))) {
     return nullptr;
   }
 
   const DatabaseSpec* spec = aDatabase->Spec();
   MOZ_ASSERT(spec);
 
   PersistenceType persistenceType = spec->metadata().persistenceType();
--- a/dom/indexedDB/test/browser.ini
+++ b/dom/indexedDB/test/browser.ini
@@ -2,27 +2,16 @@
 run-if = buildapp == "browser"
 skip-if = e10s
 support-files =
   head.js
   browser_forgetThisSiteAdd.html
   browser_forgetThisSiteGet.html
   browserHelpers.js
   browser_permissionsPrompt.html
-  browser_quotaPrompt.html
-  browser_quotaPromptDatabases.html
-  browser_quotaPromptDelete.html
   bug839193.js
   bug839193.xul
 
 [browser_forgetThisSite.js]
 [browser_permissionsPromptAllow.js]
 [browser_permissionsPromptDeny.js]
 [browser_perwindow_privateBrowsing.js]
-[browser_quotaPromptAllow.js]
-skip-if = true # Quota handling disabled for now.
-[browser_quotaPromptDeny.js]
-skip-if = true # Quota handling disabled for now.
-[browser_quotaPromptDatabases.js]
-skip-if = true # Quota handling disabled for now.
-[browser_quotaPromptDelete.js]
-skip-if = true # Quota handling disabled for now.
 [browser_bug839193.js]
deleted file mode 100644
--- a/dom/indexedDB/test/browser_quotaPrompt.html
+++ /dev/null
@@ -1,86 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-  <head>
-    <title>Indexed Database Test</title>
-
-    <script type="text/javascript;version=1.7">
-      let db;
-      let version = window.location.href.charAt(window.location.href.length - 1);
-
-      function onAddMore() {
-        let transaction = db.transaction("foo", "readwrite");
-
-        transaction.oncomplete = function(event) {
-          setTimeout(testFinishedCallback, 0, "complete");
-        }
-        transaction.onabort = function(event) {
-          setTimeout(testFinishedCallback, 0, "abort " + event.target.error.name);
-        }
-
-        let objectStore = transaction.objectStore("foo");
-        let obj = {
-          foo: "                                                              ",
-          bar: "                                                              ",
-          baz: "                                                              "
-        };
-        for (let i = 0; i < 1000; i++) {
-          objectStore.add(obj).onerror = errorHandler;
-        }
-      }
-
-      function onDone() {
-        window.removeEventListener("indexedDB-addMore", onAddMore, true);
-        window.removeEventListener("indexedDB-done", onDone, true);
-
-        let request =
-          indexedDB.open(window.location.pathname, { version: version++,
-                                                     storage: "persistent" });
-        request.onerror = errorHandler;
-        request.onupgradeneeded = function(event) {
-          db.deleteObjectStore("foo");
-          db.onversionchange = function () { db.close(); };
-          request.transaction.oncomplete = function(event) {
-            testResult = "finished";
-            testException = undefined;
-            finishTest();
-          }
-        }
-      }
-
-      function testSteps()
-      {
-        const name = window.location.pathname;
-
-        window.addEventListener("indexedDB-addMore", onAddMore, true);
-        window.addEventListener("indexedDB-done", onDone, true);
-
-        let request = indexedDB.open(name, { version: version++,
-                                             storage: "persistent" });
-        request.onerror = errorHandler;
-        request.onupgradeneeded = grabEventAndContinueHandler;
-        let event = yield undefined;
-
-        db = event.target.result;
-
-        db.onversionchange = function () { db.close(); };
-
-        db.createObjectStore("foo", { autoIncrement: true });
-
-        request.onsuccess = grabEventAndContinueHandler;
-        yield undefined;
-
-        setTimeout(testFinishedCallback, 0, "ready");
-        yield undefined;
-      }
-    </script>
-
-    <script type="text/javascript;version=1.7" src="browserHelpers.js"></script>
-
-  </head>
-
-  <body onload="runTest();" onunload="finishTestNow();"></body>
-
-</html>
deleted file mode 100644
--- a/dom/indexedDB/test/browser_quotaPromptAllow.js
+++ /dev/null
@@ -1,140 +0,0 @@
-/**
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-// Make sure this is a unique origin or the tests will randomly fail!
-const testPageURL = "http://bug704464-1.example.com/browser/" +
-  "dom/indexedDB/test/browser_quotaPrompt.html";
-const notificationID = "indexedDB-quota-prompt";
-
-function test()
-{
-  waitForExplicitFinish();
-  requestLongerTimeout(10);
-  setPermission(testPageURL, "indexedDB");
-  removePermission(testPageURL, "indexedDB-unlimited");
-  Services.prefs.setIntPref("dom.indexedDB.warningQuota", 2);
-  executeSoon(test1);
-}
-
-let addMoreTest1Count = 0;
-
-function test1()
-{
-  gBrowser.selectedTab = gBrowser.addTab();
-
-  gBrowser.selectedBrowser.addEventListener("load", function () {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-
-    let seenPopupCount;
-
-    setFinishedCallback(function(result) {
-      is(result, "ready", "Got 'ready' result");
-
-      setFinishedCallback(function(result) {
-        is(result, "complete", "Got 'complete' result");
-
-        if (addMoreTest1Count > seenPopupCount + 5) {
-          setFinishedCallback(function(result) {
-            is(result, "finished", "Got 'finished' result");
-            is(getPermission(testPageURL, "indexedDB-unlimited"),
-               Components.interfaces.nsIPermissionManager.ALLOW_ACTION,
-               "Correct permission set");
-            gBrowser.removeCurrentTab();
-            unregisterAllPopupEventHandlers();
-            executeSoon(test2);
-          });
-          executeSoon(function() { dispatchEvent("indexedDB-done"); });
-        }
-        else {
-          ++addMoreTest1Count;
-          executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
-        }
-      });
-      ++addMoreTest1Count;
-      executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
-    });
-
-    registerPopupEventHandler("popupshowing", function () {
-      ok(true, "prompt showing");
-      seenPopupCount = addMoreTest1Count;
-    });
-    registerPopupEventHandler("popupshown", function () {
-      ok(true, "prompt shown");
-      triggerMainCommand(this);
-    });
-    registerPopupEventHandler("popuphidden", function () {
-      ok(true, "prompt hidden");
-    });
-
-  }, true);
-
-  info("loading test page: " + testPageURL);
-  content.location = testPageURL + "?v=1";
-}
-
-function test2()
-{
-  gBrowser.selectedTab = gBrowser.addTab();
-
-  gBrowser.selectedBrowser.addEventListener("load", function () {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-
-    let seenPopup;
-    let addMoreCount = 0;
-
-    setFinishedCallback(function(result) {
-      is(result, "ready", "Got 'ready' result");
-      is(getPermission(testPageURL, "indexedDB-unlimited"),
-         Components.interfaces.nsIPermissionManager.ALLOW_ACTION,
-         "Correct permission set");
-
-      setFinishedCallback(function(result) {
-        is(result, "complete", "Got 'complete' result");
-        ok(!seenPopup, "No popup");
-        is(getPermission(testPageURL, "indexedDB-unlimited"),
-           Components.interfaces.nsIPermissionManager.ALLOW_ACTION,
-           "Correct permission set");
-
-        if (addMoreCount > addMoreTest1Count + 5) {
-          setFinishedCallback(function(result) {
-            is(result, "finished", "Got 'finished' result");
-            ok(!seenPopup, "No popup");
-            is(getPermission(testPageURL, "indexedDB-unlimited"),
-               Components.interfaces.nsIPermissionManager.ALLOW_ACTION,
-               "Correct permission set");
-
-            gBrowser.removeCurrentTab();
-            unregisterAllPopupEventHandlers();
-            removePermission(testPageURL, "indexedDB");
-            Services.prefs.clearUserPref("dom.indexedDB.warningQuota");
-            executeSoon(finish);
-          });
-          executeSoon(function() { dispatchEvent("indexedDB-done"); });
-        }
-        else {
-          ++addMoreCount;
-          executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
-        }
-      });
-      ++addMoreCount;
-      executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
-    });
-
-    registerPopupEventHandler("popupshowing", function () {
-      ok(false, "Shouldn't show a popup this time");
-      seenPopup = true;
-    });
-    registerPopupEventHandler("popupshown", function () {
-      ok(false, "Shouldn't show a popup this time");
-    });
-    registerPopupEventHandler("popuphidden", function () {
-      ok(false, "Shouldn't show a popup this time");
-    });
-
-  }, true);
-
-  info("loading test page: " + testPageURL);
-  content.location = testPageURL + "?v=3";
-}
deleted file mode 100644
--- a/dom/indexedDB/test/browser_quotaPromptDatabases.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-  <head>
-    <title>Indexed Database Test</title>
-
-    <script type="text/javascript;version=1.7">
-      let db;
-      let i = 0;
-
-      function onAddMore() {
-        const name = window.location.pathname + i++;
-
-        let request = indexedDB.open(name, { version: 1,
-                                             storage: "persistent" });
-        request.onerror = errorHandler;
-        request.onsuccess = grabEventAndContinueHandler;
-
-        request.onsuccess = function(event) {
-          setTimeout(testFinishedCallback, 0, "complete");
-        }
-        request.onerror = function(event) {
-          setTimeout(testFinishedCallback, 0, "abort");
-        }
-      }
-
-      function onDone() {
-        window.removeEventListener("indexedDB-addMore", onAddMore, true);
-        window.removeEventListener("indexedDB-done", onDone, true);
-
-        testResult = "finished";
-        testException = undefined;
-        finishTest();
-      }
-
-      function testSteps()
-      {
-        window.addEventListener("indexedDB-addMore", onAddMore, true);
-        window.addEventListener("indexedDB-done", onDone, true);
-
-        setTimeout(testFinishedCallback, 0, "ready");
-        yield undefined;
-      }
-    </script>
-
-    <script type="text/javascript;version=1.7" src="browserHelpers.js"></script>
-
-  </head>
-
-  <body onload="runTest();" onunload="finishTestNow();"></body>
-
-</html>
deleted file mode 100644
--- a/dom/indexedDB/test/browser_quotaPromptDatabases.js
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-// Make sure this is a unique origin or the tests will randomly fail!
-const testPageURL = "http://bug704464-3.example.com/browser/" +
-  "dom/indexedDB/test/browser_quotaPromptDatabases.html";
-const notificationID = "indexedDB-quota-prompt";
-
-function test()
-{
-  waitForExplicitFinish();
-  requestLongerTimeout(10);
-  setPermission(testPageURL, "indexedDB");
-  removePermission(testPageURL, "indexedDB-unlimited");
-  Services.prefs.setIntPref("dom.indexedDB.warningQuota", 2);
-  executeSoon(test1);
-}
-
-let addMoreTest1Count = 0;
-
-function test1()
-{
-  gBrowser.selectedTab = gBrowser.addTab();
-
-  gBrowser.selectedBrowser.addEventListener("load", function () {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-
-    let seenPopupCount;
-
-    setFinishedCallback(function(result) {
-      is(result, "ready", "Got 'ready' result");
-
-      setFinishedCallback(function(result) {
-        is(result, "complete", "Got 'complete' result");
-
-        if (addMoreTest1Count >= seenPopupCount + 5) {
-          setFinishedCallback(function(result) {
-            is(result, "finished", "Got 'finished' result");
-            is(getPermission(testPageURL, "indexedDB-unlimited"),
-               Components.interfaces.nsIPermissionManager.ALLOW_ACTION,
-               "Correct permission set");
-            gBrowser.removeCurrentTab();
-            unregisterAllPopupEventHandlers();
-            addMoreTest1Count = seenPopupCount;
-            executeSoon(finish);
-          });
-          executeSoon(function() { dispatchEvent("indexedDB-done"); });
-        }
-        else {
-          ++addMoreTest1Count;
-          executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
-        }
-      });
-      ++addMoreTest1Count;
-      executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
-    });
-
-    registerPopupEventHandler("popupshowing", function () {
-      ok(true, "prompt showing");
-      seenPopupCount = addMoreTest1Count - 1;
-    });
-    registerPopupEventHandler("popupshown", function () {
-      ok(true, "prompt shown");
-      triggerMainCommand(this);
-    });
-    registerPopupEventHandler("popuphidden", function () {
-      ok(true, "prompt hidden");
-    });
-
-  }, true);
-
-  info("loading test page: " + testPageURL);
-  content.location = testPageURL;
-}
deleted file mode 100644
--- a/dom/indexedDB/test/browser_quotaPromptDelete.html
+++ /dev/null
@@ -1,97 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-  <head>
-    <title>Indexed Database Test</title>
-
-    <script type="text/javascript;version=1.7">
-      let db;
-      let name = window.location.pathname;
-
-      function onAddMore() {
-        let transaction = db.transaction("foo", "readwrite");
-
-        transaction.oncomplete = function(event) {
-          setTimeout(testFinishedCallback, 0, "complete");
-        }
-        transaction.onabort = function(event) {
-          setTimeout(testFinishedCallback, 0, "abort");
-        }
-
-        let objectStore = transaction.objectStore("foo");
-        let obj = {
-          foo: "                                                              ",
-          bar: "                                                              ",
-          baz: "                                                              "
-        };
-        for (let i = 0; i < 1000; i++) {
-          objectStore.add(obj).onerror = errorHandler;
-        }
-      }
-
-      function onDone() {
-        window.removeEventListener("indexedDB-addMore", onAddMore, true);
-        window.removeEventListener("indexedDB-done", onDone, true);
-        window.removeEventListener("indexedDB-reset", onReset, true);
-
-        testResult = "finished";
-        testException = undefined;
-        finishTest();
-      }
-
-      function onReset() {
-        db.close();
-        // N.B. the spec provides no ordering guarantee w.r.t deleteDatabase.
-        let deleteRequest = indexedDB.deleteDatabase(name);
-
-        deleteRequest.onerror = errorHandler;
-        deleteRequest.onsuccess = function () {
-          // It is imperative that we open a different database this time.
-          let request = indexedDB.open("take2", { version: 1,
-                                                  storage: "persistent" });
-          request.onerror = errorHandler;
-          request.onupgradeneeded = function(event) {
-            db = event.target.result;
-            db.createObjectStore("foo", { autoIncrement: true });
-          }
-          request.onsuccess = function ()
-            { setTimeout(testFinishedCallback, 0, "resetDone"); };
-          request.onblocked = errorHandler;
-        }
-      }
-
-      function testSteps()
-      {
-        window.addEventListener("indexedDB-addMore", onAddMore, true);
-        window.addEventListener("indexedDB-reset", onReset, true);
-        window.addEventListener("indexedDB-done", onDone, true);
-
-        let request = indexedDB.open(name, { version: 1,
-                                             storage: "persistent" });
-        request.onerror = errorHandler;
-        request.onupgradeneeded = grabEventAndContinueHandler;
-        let event = yield undefined;
-
-        db = event.target.result;
-
-        db.onversionchange = function () { db.close(); };
-
-        db.createObjectStore("foo", { autoIncrement: true });
-
-        request.onsuccess = grabEventAndContinueHandler;
-        yield undefined;
-
-        setTimeout(testFinishedCallback, 0, "ready");
-        yield undefined;
-      }
-    </script>
-
-    <script type="text/javascript;version=1.7" src="browserHelpers.js"></script>
-
-  </head>
-
-  <body onload="runTest();" onunload="finishTestNow();"></body>
-
-</html>
deleted file mode 100644
--- a/dom/indexedDB/test/browser_quotaPromptDelete.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-// Make sure this is a unique origin or the tests will randomly fail!
-const testPageURL = "http://bug702292.example.com/browser/" +
-  "dom/indexedDB/test/browser_quotaPromptDelete.html";
-const notificationID = "indexedDB-quota-prompt";
-
-function test()
-{
-  waitForExplicitFinish();
-  requestLongerTimeout(10);
-  setPermission(testPageURL, "indexedDB");
-  removePermission(testPageURL, "indexedDB-unlimited");
-  Services.prefs.setIntPref("dom.indexedDB.warningQuota", 2);
-  executeSoon(test1);
-}
-
-let addMoreTest1Count = 0;
-let haveReset = false;
-let secondTimeCount = 0;
-
-function test1()
-{
-  gBrowser.selectedTab = gBrowser.addTab();
-
-  gBrowser.selectedBrowser.addEventListener("load", function () {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-
-    let seenPopupCount;
-
-    setFinishedCallback(function(result) {
-      is(result, "ready", "Got 'ready' result");
-
-      setFinishedCallback(function(result) {
-        if (result == "abort") {
-          setFinishedCallback(function(result) {
-            is(result, "resetDone", "Got 'resetDone' result");
-
-            function secondTimeThroughCallback(result) {
-              is(result, "complete", "Got 'complete' result");
-
-              // If we hit the quota on the Nth iteration last time, we should
-              // be able to go N-1 iterations without hitting it after
-              // obliterating the db.
-              if (++secondTimeCount < addMoreTest1Count - 1) {
-                secondTimeThroughAddMore();
-              } else {
-                setFinishedCallback(function(result) {
-                  is(result, "finished", "Got 'finished' result");
-                  is(getPermission(testPageURL, "indexedDB-unlimited"),
-                     Components.interfaces.nsIPermissionManager.DENY_ACTION,
-                     "Correct permission set");
-                  gBrowser.removeCurrentTab();
-                  unregisterAllPopupEventHandlers();
-                  executeSoon(finish);
-                });
-                executeSoon(function() { dispatchEvent("indexedDB-done"); });
-              }
-            }
-
-            function secondTimeThroughAddMore() {
-              setFinishedCallback(secondTimeThroughCallback);
-              executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
-            }
-
-            haveReset = true;
-            secondTimeThroughAddMore();
-          });
-          executeSoon(function() { dispatchEvent("indexedDB-reset"); });
-        }
-        else {
-          ++addMoreTest1Count;
-          executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
-        }
-      });
-      ++addMoreTest1Count;
-      executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
-    });
-
-    registerPopupEventHandler("popupshowing", function () {
-      ok(true, "prompt showing");
-      seenPopupCount = addMoreTest1Count - 1;
-    });
-    registerPopupEventHandler("popupshown", function () {
-      ok(true, "prompt shown");
-      ok(!haveReset, "Shouldn't get here twice!");
-      triggerSecondaryCommand(this, 0);
-    });
-    registerPopupEventHandler("popuphidden", function () {
-      ok(true, "prompt hidden");
-    });
-
-  }, true);
-
-  info("loading test page: " + testPageURL);
-  content.location = testPageURL;
-}
deleted file mode 100644
--- a/dom/indexedDB/test/browser_quotaPromptDeny.js
+++ /dev/null
@@ -1,149 +0,0 @@
-/**
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-// Make sure this is a unique origin or the tests will randomly fail!
-const testPageURL = "http://bug704464-2.example.com/browser/" +
-  "dom/indexedDB/test/browser_quotaPrompt.html";
-const notificationID = "indexedDB-quota-prompt";
-
-function test()
-{
-  waitForExplicitFinish();
-  requestLongerTimeout(10);
-  setPermission(testPageURL, "indexedDB");
-  removePermission(testPageURL, "indexedDB-unlimited");
-  Services.prefs.setIntPref("dom.indexedDB.warningQuota", 2);
-  executeSoon(test1);
-}
-
-let addMoreTest1Count = 0;
-
-function test1()
-{
-  gBrowser.selectedTab = gBrowser.addTab();
-
-  gBrowser.selectedBrowser.addEventListener("load", function () {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-
-    let seenPopupCount;
-
-    setFinishedCallback(function(result) {
-      is(result, "ready", "Got 'ready' result");
-
-      setFinishedCallback(function(result) {
-        if (!seenPopupCount) {
-          is(result, "complete", "Got 'complete' result");
-        }
-        else {
-          is(result, "abort QuotaExceededError", "Got 'abort' result");
-        }
-
-        if (addMoreTest1Count >= seenPopupCount + 5) {
-          setFinishedCallback(function(result) {
-            is(result, "finished", "Got 'finished' result");
-            is(getPermission(testPageURL, "indexedDB-unlimited"),
-               Components.interfaces.nsIPermissionManager.DENY_ACTION,
-               "Correct permission set");
-            gBrowser.removeCurrentTab();
-            unregisterAllPopupEventHandlers();
-            addMoreTest1Count = seenPopupCount;
-            executeSoon(test2);
-          });
-          executeSoon(function() { dispatchEvent("indexedDB-done"); });
-        }
-        else {
-          ++addMoreTest1Count;
-          executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
-        }
-      });
-      ++addMoreTest1Count;
-      executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
-    });
-
-    registerPopupEventHandler("popupshowing", function () {
-      ok(true, "prompt showing");
-      seenPopupCount = addMoreTest1Count - 1;
-    });
-    registerPopupEventHandler("popupshown", function () {
-      ok(true, "prompt shown");
-      triggerSecondaryCommand(this, 0);
-    });
-    registerPopupEventHandler("popuphidden", function () {
-      ok(true, "prompt hidden");
-    });
-
-  }, true);
-
-  info("loading test page: " + testPageURL);
-  content.location = testPageURL + "?v=5";
-}
-
-function test2()
-{
-  gBrowser.selectedTab = gBrowser.addTab();
-
-  gBrowser.selectedBrowser.addEventListener("load", function () {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-
-    let seenPopup;
-    let addMoreCount = 0;
-    let lastResult;
-
-    setFinishedCallback(function(result) {
-      is(result, "ready", "Got 'ready' result");
-      is(getPermission(testPageURL, "indexedDB-unlimited"),
-         Components.interfaces.nsIPermissionManager.DENY_ACTION,
-         "Correct permission set");
-
-      setFinishedCallback(function(result) {
-        info("Got '" + result + "' result");
-        lastResult = result;
-        ok(!seenPopup, "No popup");
-        is(getPermission(testPageURL, "indexedDB-unlimited"),
-           Components.interfaces.nsIPermissionManager.DENY_ACTION,
-           "Correct permission set");
-
-        if (addMoreCount > addMoreTest1Count + 5) {
-          setFinishedCallback(function(result) {
-            is(result, "finished", "Got 'finished' result");
-            is(lastResult, "abort QuotaExceededError", "Aborted as expected");
-            ok(!seenPopup, "No popup");
-            is(getPermission(testPageURL, "indexedDB-unlimited"),
-               Components.interfaces.nsIPermissionManager.DENY_ACTION,
-               "Correct permission set");
-
-            gBrowser.removeCurrentTab();
-            unregisterAllPopupEventHandlers();
-            removePermission(testPageURL, "indexedDB");
-            Services.prefs.clearUserPref("dom.indexedDB.warningQuota");
-            executeSoon(finish);
-          });
-          executeSoon(function() { dispatchEvent("indexedDB-done"); });
-        }
-        else {
-          ++addMoreCount;
-          executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
-        }
-      });
-      ++addMoreCount;
-      executeSoon(function() { dispatchEvent("indexedDB-addMore"); });
-    });
-
-    registerPopupEventHandler("popupshowing", function () {
-      ok(false, "Shouldn't show a popup this time");
-      seenPopup = true;
-    });
-    registerPopupEventHandler("popupshown", function () {
-      ok(false, "Shouldn't show a popup this time");
-    });
-    registerPopupEventHandler("popuphidden", function () {
-      ok(false, "Shouldn't show a popup this time");
-    });
-
-  }, true);
-
-  info("loading test page: " + testPageURL);
-  content.location = testPageURL + "?v=7";
-}
--- a/dom/indexedDB/test/file.js
+++ b/dom/indexedDB/test/file.js
@@ -1,15 +1,13 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-const DEFAULT_QUOTA = 50 * 1024 * 1024;
-
 var bufferCache = [];
 var utils = SpecialPowers.getDOMWindowUtils(window);
 
 function getBuffer(size)
 {
   let buffer = new ArrayBuffer(size);
   is(buffer.byteLength, size, "Correct byte length");
   return buffer;
--- a/dom/indexedDB/test/helpers.js
+++ b/dom/indexedDB/test/helpers.js
@@ -61,22 +61,20 @@ function testHarnessSteps() {
     let match = src.match(/indexedDB\/test\/unit\/(test_[^\/]+\.js)$/);
     if (match && match.length == 2) {
       testScriptPath = src;
       testScriptFilename = match[1];
       break;
     }
   }
 
-  let limitedQuota = yield undefined;
+  yield undefined;
 
   info("Running" +
-       (testScriptFilename ? " '" + testScriptFilename + "'" : "") +
-       " with " +
-       (limitedQuota ? "" : "un") + "limited quota");
+       (testScriptFilename ? " '" + testScriptFilename + "'" : ""));
 
   info("Pushing preferences");
 
   SpecialPowers.pushPrefEnv(
     {
       "set": [
         ["dom.indexedDB.testing", true],
         ["dom.indexedDB.experimental", true],
@@ -91,20 +89,16 @@ function testHarnessSteps() {
   info("Pushing permissions");
 
   SpecialPowers.pushPermissions(
     [
       {
         type: "indexedDB",
         allow: true,
         context: document
-      }, {
-        type: "indexedDB-unlimited",
-        allow: !limite