merge mozilla-inbound to mozilla-central a=merge FIREFOX_AURORA_46_BASE
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 25 Jan 2016 11:50:09 +0100
changeset 281478 67c66c2878aed17ae3096d7db483ddbb2293c503
parent 281442 ba9f38e1af50dbca0a1f8df450cc355eab143c70 (diff)
parent 281477 a0254596dc6693a6b7e931d14a53a53a2d306af1 (current diff)
child 281479 a2a6201322ad1cd09202b53b9c2cbf40b26026ee
child 281483 5ae2ccf49f97e518715e8dfbbbab4dd9eda5348c
child 281497 c39242d264c8f3ccfe1039a5cce3ec519ef7b638
child 287457 671e1d2fe00379370df4f14f1fb7396f8eae2877
push idunknown
push userunknown
push dateunknown
reviewersmerge
milestone46.0a1
merge mozilla-inbound to mozilla-central a=merge
gfx/layers/apz/test/gtest/TestOverscrollHandoff.cpp
--- a/.eslintignore
+++ b/.eslintignore
@@ -59,21 +59,19 @@ b2g/locales/en-US/b2g-l10n.js
 
 # browser/ exclusions
 browser/app/**
 browser/base/content/browser-social.js
 browser/base/content/nsContextMenu.js
 browser/base/content/sanitizeDialog.js
 browser/base/content/test/**
 browser/base/content/newtab/**
-browser/components/customizableui/**
 browser/components/downloads/**
 browser/components/feeds/**
 browser/components/migration/**
-browser/components/nsBrowserGlue.js
 browser/components/pocket/**
 browser/components/preferences/**
 browser/components/privatebrowsing/**
 browser/components/sessionstore/**
 browser/components/shell/**
 browser/components/tabview/**
 browser/components/translation/**
 browser/extensions/pdfjs/**
--- a/addon-sdk/source/lib/sdk/content/page-worker.js
+++ b/addon-sdk/source/lib/sdk/content/page-worker.js
@@ -52,16 +52,17 @@ const ChildPage = Class({
       this.rules = Rules();
       this.rules.add.apply(this.rules, [].concat(options.include));
     }
   },
 
   dispose: function() {
     pages.delete(this.id);
     this.webProgress.removeProgressListener(this);
+    this.webNav.close();
     this.webNav = null;
   },
 
   attachWorker: function() {
     if (!isValidURL(this, this.contentWindow.location.href))
       return;
 
     this.options.id = uuid().toString();
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -1119,16 +1119,19 @@ pref("dom.vr.cardboard.enabled", true);
 
 // In B2G by deafult any AudioChannelAgent is muted when created.
 pref("dom.audiochannel.mutedByDefault", true);
 
 // The app origin of bluetooth app, which is responsible for listening pairing
 // requests.
 pref("dom.bluetooth.app-origin", "app://bluetooth.gaiamobile.org");
 
+// Enable W3C WebBluetooth API and disable B2G only GATT client API.
+pref("dom.bluetooth.webbluetooth.enabled", false);
+
 // Default device name for Presentation API
 pref("dom.presentation.device.name", "Firefox OS");
 
 // Enable notification of performance timing
 pref("dom.performance.enable_notify_performance_timing", true);
 
 // Multi-screen
 pref("b2g.multiscreen.chrome_remote_url", "chrome://b2g/content/shell_remote.html");
--- a/b2g/config/aries-l/sources.xml
+++ b/b2g/config/aries-l/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="be4b291a90b371b41b62ade68c31ad173bb87baa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="d3c9acb642baee501cff89e4efdb16b0c7480760">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="d3c9acb642baee501cff89e4efdb16b0c7480760">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk-specific things and forks -->
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="d3c9acb642baee501cff89e4efdb16b0c7480760">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
@@ -134,17 +134,17 @@
   <project name="platform/external/icu4c" path="external/icu4c" remote="aosp" revision="b4c6379528887dc25ca9991a535a8d92a61ad6b6"/>
   <project name="platform_frameworks_av" path="frameworks/av" remote="b2g" revision="2da3a2d5100f8afa1229bb50aa2a29ea0aaf8417"/>
   <project name="platform_system_core" path="system/core" remote="b2g" revision="8586f55fe4b015911b48e731b69c592ad82a0807"/>
   <default remote="caf" revision="refs/tags/android-4.4.2_r1" sync-j="4"/>
   <!-- Emulator specific things -->
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="72ffdf71c68a96309212eb13d63560d66db14c9e"/>
   <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="566810728cd485ff2f30766499d32ada7cbd487a"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="3e85c4683c121530c1c3a48c696a569bf5f587e2"/>
-  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="39bdda3051dd1d96da3ab369bc654290cb8d463c"/>
+  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="3e4affc1794fef1ad96d6fcc727cca92b032a429"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="f37bd545063039e30a92f2550ae78c0e6e4e2d08"/>
   <project name="platform_external_wpa_supplicant_8" path="external/wpa_supplicant_8" remote="b2g" revision="0c6a6547cd1fd302fa2b0f6e375654df36bf0ec4"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="c0dd0098328f3992e1ca09d6d4355729243863d5"/>
   <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="5f4b68c799927b6e078f987b12722c3a6ccd4a45"/>
   <project name="platform/development" path="development" revision="5968ff4e13e0d696ad8d972281fc27ae5a12829b"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="0c0c050518705d49531375012fa2b4e95e1b3693"/>
   <project name="android-sdk" path="sdk" remote="b2g" revision="0951179277915335251c5e11d242e4e1a8c2236f"/>
   <project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="be4b291a90b371b41b62ade68c31ad173bb87baa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk-specific things and forks -->
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="d3c9acb642baee501cff89e4efdb16b0c7480760">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "385ec34c8fe447342e81a40b4e1cc9a80f37fc33", 
+        "git_revision": "4023297b16fdc46de3ddb04be4f3c575313d1cde", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "c53c24531e4d32550f37c5ff5359eb70af822a73", 
+    "revision": "1520b4ebcfc727b7153be5242339b8f577ab65b4", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4-kk/sources.xml
+++ b/b2g/config/nexus-4-kk/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="d3c9acb642baee501cff89e4efdb16b0c7480760">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="385ec34c8fe447342e81a40b4e1cc9a80f37fc33"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4023297b16fdc46de3ddb04be4f3c575313d1cde"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="35dccb3127db8f39f20b985ad312d2cd44780669"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="be4b291a90b371b41b62ade68c31ad173bb87baa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -5,16 +5,17 @@
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["CustomizableUI"];
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PanelWideWidgetTracker",
   "resource:///modules/PanelWideWidgetTracker.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CustomizableWidgets",
   "resource:///modules/CustomizableWidgets.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
   "resource://gre/modules/DeferredTask.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
@@ -36,17 +37,16 @@ const kSpecialWidgetPfx = "customizableu
 const kPrefCustomizationState        = "browser.uiCustomization.state";
 const kPrefCustomizationAutoAdd      = "browser.uiCustomization.autoAdd";
 const kPrefCustomizationDebug        = "browser.uiCustomization.debug";
 const kPrefDrawInTitlebar            = "browser.tabs.drawInTitlebar";
 const kPrefWebIDEInNavbar            = "devtools.webide.widget.inNavbarByDefault";
 
 const kExpectedWindowURL = "chrome://browser/content/browser.xul";
 
-
 /**
  * The keys are the handlers that are fired when the event type (the value)
  * is fired on the subview. A widget that provides a subview has the option
  * of providing onViewShowing and onViewHiding event handlers.
  */
 const kSubviewEvents = [
   "ViewShowing",
   "ViewHiding"
@@ -151,22 +151,33 @@ var gSingleWrapperCache = new WeakMap();
 var gListeners = new Set();
 
 var gUIStateBeforeReset = {
   uiCustomizationState: null,
   drawInTitlebar: null,
   gUIStateBeforeReset: null,
 };
 
-var gModuleName = "[CustomizableUI]";
-#include logging.js
+XPCOMUtils.defineLazyGetter(this, "log", () => {
+  let scope = {};
+  Cu.import("resource://gre/modules/Console.jsm", scope);
+  let debug;
+  try {
+    debug = Services.prefs.getBoolPref(kPrefCustomizationDebug);
+  } catch (ex) {}
+  let consoleOptions = {
+    maxLogLevel: debug ? "all" : "log",
+    prefix: "CustomizableUI",
+  };
+  return new scope.ConsoleAPI(consoleOptions);
+});
 
 var CustomizableUIInternal = {
   initialize: function() {
-    LOG("Initializing");
+    log.debug("Initializing");
 
     this.addListener(this);
     this._defineBuiltInWidgets();
     this.loadSavedState();
     this._introduceNewBuiltinWidgets();
     this._markObsoleteBuiltinButtonsSeen();
 
     let panelPlacements = [
@@ -176,30 +187,31 @@ var CustomizableUIInternal = {
       "privatebrowsing-button",
       "save-page-button",
       "print-button",
       "history-panelmenu",
       "fullscreen-button",
       "find-button",
       "preferences-button",
       "add-ons-button",
-#ifndef MOZ_DEV_EDITION
-      "developer-button",
-#endif
       "sync-button",
     ];
 
-#ifdef E10S_TESTING_ONLY
-    if (gPalette.has("e10s-button")) {
-      let newWindowIndex = panelPlacements.indexOf("new-window-button");
-      if (newWindowIndex > -1) {
-        panelPlacements.splice(newWindowIndex + 1, 0, "e10s-button");
+    if (!AppConstants.MOZ_DEV_EDITION) {
+      panelPlacements.splice(-1, 0, "developer-button");
+    }
+
+    if (AppConstants.E10S_TESTING_ONLY) {
+      if (gPalette.has("e10s-button")) {
+        let newWindowIndex = panelPlacements.indexOf("new-window-button");
+        if (newWindowIndex > -1) {
+          panelPlacements.splice(newWindowIndex + 1, 0, "e10s-button");
+        }
       }
     }
-#endif
 
     let showCharacterEncoding = Services.prefs.getComplexValue(
       "browser.menu.showCharacterEncoding",
       Ci.nsIPrefLocalizedString
     ).data;
     if (showCharacterEncoding == "true") {
       panelPlacements.push("characterencoding-button");
     }
@@ -209,59 +221,61 @@ var CustomizableUIInternal = {
       type: CustomizableUI.TYPE_MENU_PANEL,
       defaultPlacements: panelPlacements
     }, true);
     PanelWideWidgetTracker.init();
 
     let navbarPlacements = [
       "urlbar-container",
       "search-container",
-#ifdef MOZ_DEV_EDITION
-      "developer-button",
-#endif
       "bookmarks-menu-button",
       "downloads-button",
       "home-button",
       "loop-button",
     ];
 
+    if (AppConstants.MOZ_DEV_EDITION) {
+      navbarPlacements.splice(2, 0, "developer-button");
+    }
+
     if (Services.prefs.getBoolPref(kPrefWebIDEInNavbar)) {
       navbarPlacements.push("webide-button");
     }
 
     this.registerArea(CustomizableUI.AREA_NAVBAR, {
       legacy: true,
       type: CustomizableUI.TYPE_TOOLBAR,
       overflowable: true,
       defaultPlacements: navbarPlacements,
       defaultCollapsed: false,
     }, true);
-#ifndef XP_MACOSX
-    this.registerArea(CustomizableUI.AREA_MENUBAR, {
-      legacy: true,
-      type: CustomizableUI.TYPE_TOOLBAR,
-      defaultPlacements: [
-        "menubar-items",
-      ],
-      get defaultCollapsed() {
-#ifdef MENUBAR_CAN_AUTOHIDE
-#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
-        return true;
-#else
-        // This is duplicated logic from /browser/base/jar.mn
-        // for win6BrowserOverlay.xul.
-        return Services.appinfo.OS == "WINNT" &&
-               Services.sysinfo.getProperty("version") != "5.1";
-#endif
-#else
-        return false;
-#endif
-      }
-    }, true);
-#endif
+
+    if (AppConstants.platform != "macosx") {
+      this.registerArea(CustomizableUI.AREA_MENUBAR, {
+        legacy: true,
+        type: CustomizableUI.TYPE_TOOLBAR,
+        defaultPlacements: [
+          "menubar-items",
+        ],
+        get defaultCollapsed() {
+          if (AppConstants.MENUBAR_CAN_AUTOHIDE) {
+            if (AppConstants.platform == "linux") {
+              return true;
+            } else {
+              // This is duplicated logic from /browser/base/jar.mn
+              // for win6BrowserOverlay.xul.
+              return AppConstants.isPlatformAndVersionAtLeast("win", 6);
+            }
+          } else {
+            return false;
+          }
+        }
+      }, true);
+    }
+
     this.registerArea(CustomizableUI.AREA_TABSTRIP, {
       legacy: true,
       type: CustomizableUI.TYPE_TOOLBAR,
       defaultPlacements: [
         "tabbrowser-tabs",
         "new-tab-button",
         "alltabs-button",
       ],
@@ -280,25 +294,26 @@ var CustomizableUIInternal = {
       type: CustomizableUI.TYPE_TOOLBAR,
       legacy: true,
       defaultPlacements: ["addonbar-closebutton", "status-bar"],
       defaultCollapsed: false,
     }, true);
   },
 
   get _builtinToolbars() {
-    return new Set([
+    let toolbars = new Set([
       CustomizableUI.AREA_NAVBAR,
       CustomizableUI.AREA_BOOKMARKS,
       CustomizableUI.AREA_TABSTRIP,
       CustomizableUI.AREA_ADDONBAR,
-#ifndef XP_MACOSX
-      CustomizableUI.AREA_MENUBAR,
-#endif
     ]);
+    if (AppConstants.platform != "macosx") {
+      toolbars.add(CustomizableUI.AREA_MENUBAR);
+    }
+    return toolbars;
   },
 
   _defineBuiltInWidgets: function() {
     for (let widgetDefinition of CustomizableWidgets) {
       this.createBuiltinWidget(widgetDefinition);
     }
   },
 
@@ -686,17 +701,17 @@ var CustomizableUIInternal = {
 
         if (this.isSpecialWidget(id) && areaIsPanel) {
           placementsToRemove.add(id);
           continue;
         }
 
         let [provider, node] = this.getWidgetNode(id, window);
         if (!node) {
-          LOG("Unknown widget: " + id);
+          log.debug("Unknown widget: " + id);
           continue;
         }
 
         // If the placements have items in them which are (now) no longer removable,
         // we shouldn't be moving them:
         if (provider == CustomizableUI.PROVIDER_API) {
           let widgetInfo = gPalette.get(id);
           if (!widgetInfo.removable && aArea != widgetInfo.defaultArea) {
@@ -751,18 +766,18 @@ var CustomizableUIInternal = {
               if (palette && !this.isSpecialWidget(node.id)) {
                 palette.appendChild(node);
                 this.removeLocationAttributes(node);
               } else {
                 container.removeChild(node);
               }
             } else {
               node.setAttribute("removable", false);
-              LOG("Adding non-removable widget to placements of " + aArea + ": " +
-                  node.id);
+              log.debug("Adding non-removable widget to placements of " + aArea + ": " +
+                        node.id);
               gPlacements.get(aArea).push(node.id);
               gDirty = true;
             }
           }
           node = previousSibling;
         }
       }
 
@@ -851,33 +866,33 @@ var CustomizableUIInternal = {
                        this.createSpecialWidget(aWidgetId, document);
       return [ CustomizableUI.PROVIDER_SPECIAL, widgetNode];
     }
 
     let widget = gPalette.get(aWidgetId);
     if (widget) {
       // If we have an instance of this widget already, just use that.
       if (widget.instances.has(document)) {
-        LOG("An instance of widget " + aWidgetId + " already exists in this "
-            + "document. Reusing.");
+        log.debug("An instance of widget " + aWidgetId + " already exists in this "
+                  + "document. Reusing.");
         return [ CustomizableUI.PROVIDER_API,
                  widget.instances.get(document) ];
       }
 
       return [ CustomizableUI.PROVIDER_API,
                this.buildWidget(document, widget) ];
     }
 
-    LOG("Searching for " + aWidgetId + " in toolbox.");
+    log.debug("Searching for " + aWidgetId + " in toolbox.");
     let node = this.findWidgetInWindow(aWidgetId, aWindow);
     if (node) {
       return [ CustomizableUI.PROVIDER_XUL, node ];
     }
 
-    LOG("No node for " + aWidgetId + " found.");
+    log.debug("No node for " + aWidgetId + " found.");
     return [null, null];
   },
 
   registerMenuPanel: function(aPanelContents) {
     if (gBuildAreas.has(CustomizableUI.AREA_PANEL) &&
         gBuildAreas.get(CustomizableUI.AREA_PANEL).has(aPanelContents)) {
       return;
     }
@@ -937,17 +952,17 @@ var CustomizableUIInternal = {
 
       let container = areaNode.customizationTarget;
       let widgetNode = window.document.getElementById(aWidgetId);
       if (widgetNode && isOverflowable) {
         container = areaNode.overflowable.getContainerFor(widgetNode);
       }
 
       if (!widgetNode || !container.contains(widgetNode)) {
-        INFO("Widget " + aWidgetId + " not found, unable to remove from " + aArea);
+        log.info("Widget " + aWidgetId + " not found, unable to remove from " + aArea);
         continue;
       }
 
       this.notifyListeners("onWidgetBeforeDOMChange", widgetNode, null, container, true);
 
       // We remove location attributes here to make sure they're gone too when a
       // widget is removed from a toolbar to the palette. See bug 930950.
       this.removeLocationAttributes(widgetNode);
@@ -1089,18 +1104,18 @@ var CustomizableUIInternal = {
   insertNode: function(aWidgetId, aArea, aPosition, isNew) {
     let areaNodes = gBuildAreas.get(aArea);
     if (!areaNodes) {
       return;
     }
 
     let placements = gPlacements.get(aArea);
     if (!placements) {
-      ERROR("Could not find any placements for " + aArea +
-            " when moving a widget.");
+      log.error("Could not find any placements for " + aArea +
+                " when moving a widget.");
       return;
     }
 
     // Go through each of the nodes associated with this area and move the
     // widget to the requested location.
     for (let areaNode of areaNodes) {
       this.insertNodeInWindow(aWidgetId, areaNode, isNew);
     }
@@ -1113,17 +1128,17 @@ var CustomizableUIInternal = {
                               : true;
 
     if (!showInPrivateBrowsing && PrivateBrowsingUtils.isWindowPrivate(window)) {
       return;
     }
 
     let [, widgetNode] = this.getWidgetNode(aWidgetId, window);
     if (!widgetNode) {
-      ERROR("Widget '" + aWidgetId + "' not found, unable to move");
+      log.error("Widget '" + aWidgetId + "' not found, unable to move");
       return;
     }
 
     let areaId = aAreaNode.id;
     if (isNew) {
       this.ensureButtonContextMenu(widgetNode, aAreaNode);
       if (widgetNode.localName == "toolbarbutton" && areaId == CustomizableUI.AREA_PANEL) {
         widgetNode.setAttribute("wrap", "true");
@@ -1233,17 +1248,17 @@ var CustomizableUIInternal = {
    * for an API-provided widget or a special widget.
    */
   findWidgetInWindow: function(aId, aWindow) {
     if (!gBuildWindows.has(aWindow)) {
       throw new Error("Build window not registered");
     }
 
     if (!aId) {
-      ERROR("findWidgetInWindow was passed an empty string.");
+      log.error("findWidgetInWindow was passed an empty string.");
       return null;
     }
 
     let document = aWindow.document;
 
     // look for a node with the same id, as the node may be
     // in a different toolbar.
     let node = document.getElementById(aId);
@@ -1300,25 +1315,25 @@ var CustomizableUIInternal = {
     }
     if (typeof aWidget == "string") {
       aWidget = gPalette.get(aWidget);
     }
     if (!aWidget) {
       throw new Error("buildWidget was passed a non-widget to build.");
     }
 
-    LOG("Building " + aWidget.id + " of type " + aWidget.type);
+    log.debug("Building " + aWidget.id + " of type " + aWidget.type);
 
     let node;
     if (aWidget.type == "custom") {
       if (aWidget.onBuild) {
         node = aWidget.onBuild(aDocument);
       }
       if (!node || !(node instanceof aDocument.defaultView.XULElement))
-        ERROR("Custom widget with id " + aWidget.id + " does not return a valid node");
+        log.error("Custom widget with id " + aWidget.id + " does not return a valid node");
     }
     else {
       if (aWidget.onBeforeCreated) {
         aWidget.onBeforeCreated(aDocument);
       }
       node = aDocument.createElementNS(kNSXUL, "toolbarbutton");
 
       node.setAttribute("id", aWidget.id);
@@ -1331,18 +1346,18 @@ var CustomizableUIInternal = {
       node.setAttribute("overflows", aWidget.overflows);
       node.setAttribute("label", this.getLocalizedProperty(aWidget, "label"));
       let additionalTooltipArguments = [];
       if (aWidget.shortcutId) {
         let keyEl = aDocument.getElementById(aWidget.shortcutId);
         if (keyEl) {
           additionalTooltipArguments.push(ShortcutUtils.prettifyShortcut(keyEl));
         } else {
-          ERROR("Key element with id '" + aWidget.shortcutId + "' for widget '" + aWidget.id +
-                "' not found!");
+          log.error("Key element with id '" + aWidget.shortcutId + "' for widget '" + aWidget.id +
+                    "' not found!");
         }
       }
 
       let tooltip = this.getLocalizedProperty(aWidget, "tooltiptext", additionalTooltipArguments);
       if (tooltip) {
         node.setAttribute("tooltiptext", tooltip);
       }
       node.setAttribute("class", "toolbarbutton-1 chromeclass-toolbar-additional");
@@ -1350,35 +1365,35 @@ var CustomizableUIInternal = {
       let commandHandler = this.handleWidgetCommand.bind(this, aWidget, node);
       node.addEventListener("command", commandHandler, false);
       let clickHandler = this.handleWidgetClick.bind(this, aWidget, node);
       node.addEventListener("click", clickHandler, false);
 
       // If the widget has a view, and has view showing / hiding listeners,
       // hook those up to this widget.
       if (aWidget.type == "view") {
-        LOG("Widget " + aWidget.id + " has a view. Auto-registering event handlers.");
+        log.debug("Widget " + aWidget.id + " has a view. Auto-registering event handlers.");
         let viewNode = aDocument.getElementById(aWidget.viewId);
 
         if (viewNode) {
           // PanelUI relies on the .PanelUI-subView class to be able to show only
           // one sub-view at a time.
           viewNode.classList.add("PanelUI-subView");
 
           for (let eventName of kSubviewEvents) {
             let handler = "on" + eventName;
             if (typeof aWidget[handler] == "function") {
               viewNode.addEventListener(eventName, aWidget[handler], false);
             }
           }
 
-          LOG("Widget " + aWidget.id + " showing and hiding event handlers set.");
+          log.debug("Widget " + aWidget.id + " showing and hiding event handlers set.");
         } else {
-          ERROR("Could not find the view node with id: " + aWidget.viewId +
-                ", for widget: " + aWidget.id + ".");
+          log.error("Could not find the view node with id: " + aWidget.viewId +
+                    ", for widget: " + aWidget.id + ".");
         }
       }
 
       if (aWidget.onCreated) {
         aWidget.onCreated(node);
       }
     }
 
@@ -1414,17 +1429,17 @@ var CustomizableUIInternal = {
         return gWidgetsBundle.formatStringFromName(name, aFormatArgs,
           aFormatArgs.length) || def;
       }
       return gWidgetsBundle.GetStringFromName(name) || def;
     } catch(ex) {
       // If an empty string was explicitly passed, treat it as an actual
       // value rather than a missing property.
       if (!def && (name != "" || kReqStringProps.includes(aProp))) {
-        ERROR("Could not localize property '" + name + "'.");
+        log.error("Could not localize property '" + name + "'.");
       }
     }
     return def;
   },
 
   addShortcut: function(aShortcutNode, aTargetNode) {
     if (!aTargetNode)
       aTargetNode = aShortcutNode;
@@ -1446,24 +1461,24 @@ var CustomizableUIInternal = {
     if (!shortcut) {
       return;
     }
 
     aTargetNode.setAttribute("shortcut", ShortcutUtils.prettifyShortcut(shortcut));
   },
 
   handleWidgetCommand: function(aWidget, aNode, aEvent) {
-    LOG("handleWidgetCommand");
+    log.debug("handleWidgetCommand");
 
     if (aWidget.type == "button") {
       if (aWidget.onCommand) {
         try {
           aWidget.onCommand.call(null, aEvent);
         } catch (e) {
-          ERROR(e);
+          log.error(e);
         }
       } else {
         //XXXunf Need to think this through more, and formalize.
         Services.obs.notifyObservers(aNode,
                                      "customizedui-widget-command",
                                      aWidget.id);
       }
     } else if (aWidget.type == "view") {
@@ -1477,17 +1492,17 @@ var CustomizableUIInternal = {
           anchor = wrapper.anchor;
         }
       }
       ownerWindow.PanelUI.showSubView(aWidget.viewId, anchor, area);
     }
   },
 
   handleWidgetClick: function(aWidget, aNode, aEvent) {
-    LOG("handleWidgetClick");
+    log.debug("handleWidgetClick");
     if (aWidget.onClick) {
       try {
         aWidget.onClick.call(null, aEvent);
       } catch(e) {
         Cu.reportError(e);
       }
     } else {
       //XXXunf Need to think this through more, and formalize.
@@ -1641,17 +1656,17 @@ var CustomizableUIInternal = {
       // If consumers don't want this to happen, they should specify the closemenu
       // attribute.
 
     } else if (aEvent.type != "command") { // mouse events:
       if (aEvent.defaultPrevented || aEvent.button != 0) {
         return;
       }
       let isInteractive = this._isOnInteractiveElement(aEvent);
-      LOG("maybeAutoHidePanel: interactive ? " + isInteractive);
+      log.debug("maybeAutoHidePanel: interactive ? " + isInteractive);
       if (isInteractive) {
         return;
       }
     }
 
     // We can't use event.target because we might have passed a panelview
     // anonymous content boundary as well, and so target points to the
     // panelmultiview in that case. Unfortunately, this means we get
@@ -1701,19 +1716,19 @@ var CustomizableUIInternal = {
     for (let [id, widget] of gPalette) {
       if (!widget.currentArea) {
         if (widget.showInPrivateBrowsing || !isWindowPrivate) {
           widgets.add(id);
         }
       }
     }
 
-    LOG("Iterating the actual nodes of the window palette");
+    log.debug("Iterating the actual nodes of the window palette");
     for (let node of aWindowPalette.children) {
-      LOG("In palette children: " + node.id);
+      log.debug("In palette children: " + node.id);
       if (node.id && !this.getPlacementOfWidget(node.id)) {
         widgets.add(node.id);
       }
     }
 
     return [...widgets];
   },
 
@@ -1902,33 +1917,33 @@ var CustomizableUIInternal = {
   // built lazily - and therefore wouldn't otherwise result in restoring its
   // state immediately when a browser window opens, which is important for
   // other consumers of this API.
   loadSavedState: function() {
     let state = null;
     try {
       state = Services.prefs.getCharPref(kPrefCustomizationState);
     } catch (e) {
-      LOG("No saved state found");
+      log.debug("No saved state found");
       // This will fail if nothing has been customized, so silently fall back to
       // the defaults.
     }
 
     if (!state) {
       return;
     }
     try {
       gSavedState = JSON.parse(state);
       if (typeof gSavedState != "object" || gSavedState === null) {
         throw "Invalid saved state";
       }
     } catch(e) {
       Services.prefs.clearUserPref(kPrefCustomizationState);
       gSavedState = {};
-      LOG("Error loading saved UI customization state, falling back to defaults.");
+      log.debug("Error loading saved UI customization state, falling back to defaults.");
     }
 
     if (!("placements" in gSavedState)) {
       gSavedState.placements = {};
     }
 
     if (!("currentVersion" in gSavedState)) {
       gSavedState.currentVersion = 0;
@@ -1943,46 +1958,46 @@ var CustomizableUIInternal = {
     let placementsPreexisted = gPlacements.has(aArea);
 
     this.beginBatchUpdate();
     try {
       gRestoring = true;
 
       let restored = false;
       if (placementsPreexisted) {
-        LOG("Restoring " + aArea + " from pre-existing placements");
+        log.debug("Restoring " + aArea + " from pre-existing placements");
         for (let [position, id] in Iterator(gPlacements.get(aArea))) {
           this.moveWidgetWithinArea(id, position);
         }
         gDirty = false;
         restored = true;
       } else {
         gPlacements.set(aArea, []);
       }
 
       if (!restored && gSavedState && aArea in gSavedState.placements) {
-        LOG("Restoring " + aArea + " from saved state");
+        log.debug("Restoring " + aArea + " from saved state");
         let placements = gSavedState.placements[aArea];
         for (let id of placements)
           this.addWidgetToArea(id, aArea);
         gDirty = false;
         restored = true;
       }
 
       if (!restored && aLegacyState) {
-        LOG("Restoring " + aArea + " from legacy state");
+        log.debug("Restoring " + aArea + " from legacy state");
         for (let id of aLegacyState)
           this.addWidgetToArea(id, aArea);
         // Don't override dirty state, to ensure legacy state is saved here and
         // therefore only used once.
         restored = true;
       }
 
       if (!restored) {
-        LOG("Restoring " + aArea + " from default state");
+        log.debug("Restoring " + aArea + " from default state");
         let defaults = gAreas.get(aArea).get("defaultPlacements");
         if (defaults) {
           for (let id of defaults)
             this.addWidgetToArea(id, aArea, null, true);
         }
         gDirty = false;
       }
 
@@ -1990,17 +2005,17 @@ var CustomizableUIInternal = {
       // to be restored. This can occur when add-ons register widgets for a
       // lazily-restored area before it's been restored.
       if (gFuturePlacements.has(aArea)) {
         for (let id of gFuturePlacements.get(aArea))
           this.addWidgetToArea(id, aArea);
         gFuturePlacements.delete(aArea);
       }
 
-      LOG("Placements for " + aArea + ":\n\t" + gPlacements.get(aArea).join("\n\t"));
+      log.debug("Placements for " + aArea + ":\n\t" + gPlacements.get(aArea).join("\n\t"));
 
       gRestoring = false;
     } finally {
       this.endBatchUpdate();
     }
   },
 
   saveState: function() {
@@ -2021,19 +2036,19 @@ var CustomizableUIInternal = {
       for (let area of Object.keys(gSavedState.placements)) {
         if (!state.placements.has(area)) {
           let placements = gSavedState.placements[area];
           state.placements.set(area, placements);
         }
       }
     }
 
-    LOG("Saving state.");
+    log.debug("Saving state.");
     let serialized = JSON.stringify(state, this.serializerHelper);
-    LOG("State saved as: " + serialized);
+    log.debug("State saved as: " + serialized);
     Services.prefs.setCharPref(kPrefCustomizationState, serialized);
     gDirty = false;
   },
 
   serializerHelper: function(aKey, aValue) {
     if (typeof aValue == "object" && aValue.constructor.name == "Map") {
       let result = {};
       for (let [mapKey, mapValue] of aValue)
@@ -2082,17 +2097,17 @@ var CustomizableUIInternal = {
     }
 
     for (let listener of gListeners) {
       try {
         if (typeof listener[aEvent] == "function") {
           listener[aEvent].apply(listener, aArgs);
         }
       } catch (e) {
-        ERROR(e + " -- " + e.fileName + ":" + e.lineNumber);
+        log.error(e + " -- " + e.fileName + ":" + e.lineNumber);
       }
     }
   },
 
   _dispatchToolboxEventToWindow: function(aEventType, aDetails, aWindow) {
     let evt = new aWindow.CustomEvent(aEventType, {
       bubbles: true,
       cancelable: true,
@@ -2109,17 +2124,18 @@ var CustomizableUIInternal = {
       this._dispatchToolboxEventToWindow(aEventType, aDetails, win);
     }
   },
 
   createWidget: function(aProperties) {
     let widget = this.normalizeWidget(aProperties, CustomizableUI.SOURCE_EXTERNAL);
     //XXXunf This should probably throw.
     if (!widget) {
-      return;
+      log.error("unable to normalize widget");
+      return undefined;
     }
 
     gPalette.set(widget.id, widget);
 
     // Clear our caches:
     gGroupWrapperCache.delete(widget.id);
     for (let [win, ] of gBuildWindows) {
       let cache = gSingleWrapperCache.get(win);
@@ -2236,21 +2252,21 @@ var CustomizableUIInternal = {
     // destroyed and removed from the area based on criteria that may not be
     // available when the widget is created -- for example, because some other
     // feature in the browser supersedes the widget.
     let conditionalDestroyPromise = aData.conditionalDestroyPromise || null;
     delete aData.conditionalDestroyPromise;
 
     let widget = this.normalizeWidget(aData, CustomizableUI.SOURCE_BUILTIN);
     if (!widget) {
-      ERROR("Error creating builtin widget: " + aData.id);
+      log.error("Error creating builtin widget: " + aData.id);
       return;
     }
 
-    LOG("Creating built-in widget with id: " + widget.id);
+    log.debug("Creating built-in widget with id: " + widget.id);
     gPalette.set(widget.id, widget);
 
     if (conditionalDestroyPromise) {
       conditionalDestroyPromise.then(shouldDestroy => {
         if (shouldDestroy) {
           this.destroyWidget(widget.id);
           this.removeWidgetFromArea(widget.id);
         }
@@ -2280,28 +2296,28 @@ var CustomizableUIInternal = {
       defaultArea: null,
       shortcutId: null,
       tooltiptext: null,
       showInPrivateBrowsing: true,
       _introducedInVersion: -1,
     };
 
     if (typeof aData.id != "string" || !/^[a-z0-9-_]{1,}$/i.test(aData.id)) {
-      ERROR("Given an illegal id in normalizeWidget: " + aData.id);
+      log.error("Given an illegal id in normalizeWidget: " + aData.id);
       return null;
     }
 
     delete widget.implementation.currentArea;
     widget.implementation.__defineGetter__("currentArea", () => widget.currentArea);
 
     const kReqStringProps = ["id"];
     for (let prop of kReqStringProps) {
       if (typeof aData[prop] != "string") {
-        ERROR("Missing required property '" + prop + "' in normalizeWidget: "
-              + aData.id);
+        log.error("Missing required property '" + prop + "' in normalizeWidget: "
+                  + aData.id);
         return null;
       }
       widget[prop] = aData[prop];
     }
 
     const kOptStringProps = ["label", "tooltiptext", "shortcutId"];
     for (let prop of kOptStringProps) {
       if (typeof aData[prop] == "string") {
@@ -2316,19 +2332,19 @@ var CustomizableUIInternal = {
       }
     }
 
     // When we normalize builtin widgets, areas have not yet been registered:
     if (aData.defaultArea &&
         (aSource == CustomizableUI.SOURCE_BUILTIN || gAreas.has(aData.defaultArea))) {
       widget.defaultArea = aData.defaultArea;
     } else if (!widget.removable) {
-      ERROR("Widget '" + widget.id + "' is not removable but does not specify " +
-            "a valid defaultArea. That's not possible; it must specify a " +
-            "valid defaultArea as well.");
+      log.error("Widget '" + widget.id + "' is not removable but does not specify " +
+                "a valid defaultArea. That's not possible; it must specify a " +
+                "valid defaultArea as well.");
       return null;
     }
 
     if ("type" in aData && gSupportedWidgetTypes.has(aData.type)) {
       widget.type = aData.type;
     } else {
       widget.type = "button";
     }
@@ -2345,18 +2361,18 @@ var CustomizableUIInternal = {
     this.wrapWidgetEventHandler("onDestroyed", widget);
 
     if (widget.type == "button") {
       widget.onCommand = typeof aData.onCommand == "function" ?
                            aData.onCommand :
                            null;
     } else if (widget.type == "view") {
       if (typeof aData.viewId != "string") {
-        ERROR("Expected a string for widget " + widget.id + " viewId, but got "
-              + aData.viewId);
+        log.error("Expected a string for widget " + widget.id + " viewId, but got "
+                  + aData.viewId);
         return null;
       }
       widget.viewId = aData.viewId;
 
       this.wrapWidgetEventHandler("onViewShowing", widget);
       this.wrapWidgetEventHandler("onViewHiding", widget);
     } else if (widget.type == "custom") {
       this.wrapWidgetEventHandler("onBuild", widget);
@@ -2497,17 +2513,17 @@ var CustomizableUIInternal = {
       gUIStateBeforeReset.drawInTitlebar = Services.prefs.getBoolPref(kPrefDrawInTitlebar);
       gUIStateBeforeReset.uiCustomizationState = Services.prefs.getCharPref(kPrefCustomizationState);
     } catch(e) { }
 
     this._resetExtraToolbars();
 
     Services.prefs.clearUserPref(kPrefCustomizationState);
     Services.prefs.clearUserPref(kPrefDrawInTitlebar);
-    LOG("State reset");
+    log.debug("State reset");
 
     // Reset placements to make restoring default placements possible.
     gPlacements = new Map();
     gDirtyAreaCache = new Set();
     gSeenWidgets = new Set();
     // Clear the saved state to ensure that defaults will be used.
     gSavedState = null;
     // Restore the state for each area to its defaults
@@ -2724,39 +2740,39 @@ var CustomizableUIInternal = {
           });
         }
 
         if (props.get("type") == CustomizableUI.TYPE_TOOLBAR) {
           let attribute = container.getAttribute("type") == "menubar" ? "autohide" : "collapsed";
           let collapsed = container.getAttribute(attribute) == "true";
           let defaultCollapsed = props.get("defaultCollapsed");
           if (defaultCollapsed !== null && collapsed != defaultCollapsed) {
-            LOG("Found " + areaId + " had non-default toolbar visibility (expected " + defaultCollapsed + ", was " + collapsed + ")");
+            log.debug("Found " + areaId + " had non-default toolbar visibility (expected " + defaultCollapsed + ", was " + collapsed + ")");
             return false;
           }
         }
       }
-      LOG("Checking default state for " + areaId + ":\n" + currentPlacements.join(",") +
-          "\nvs.\n" + defaultPlacements.join(","));
+      log.debug("Checking default state for " + areaId + ":\n" + currentPlacements.join(",") +
+                "\nvs.\n" + defaultPlacements.join(","));
 
       if (currentPlacements.length != defaultPlacements.length) {
         return false;
       }
 
       for (let i = 0; i < currentPlacements.length; ++i) {
         if (currentPlacements[i] != defaultPlacements[i]) {
-          LOG("Found " + currentPlacements[i] + " in " + areaId + " where " +
-              defaultPlacements[i] + " was expected!");
+          log.debug("Found " + currentPlacements[i] + " in " + areaId + " where " +
+                    defaultPlacements[i] + " was expected!");
           return false;
         }
       }
     }
 
     if (Services.prefs.prefHasUserValue(kPrefDrawInTitlebar)) {
-      LOG(kPrefDrawInTitlebar + " pref is non-default");
+      log.debug(kPrefDrawInTitlebar + " pref is non-default");
       return false;
     }
 
     return true;
   },
 
   setToolbarVisibility: function(aToolbarId, aIsVisible) {
     // We only persist the attribute the first time.
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -5,16 +5,17 @@
 "use strict";
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 this.EXPORTED_SYMBOLS = ["CustomizableWidgets"];
 
 Cu.import("resource:///modules/CustomizableUI.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
   "resource:///modules/BrowserUITelemetry.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUIUtils",
   "resource:///modules/PlacesUIUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "RecentlyClosedTabsAndWindowsMenuUtils",
   "resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm");
@@ -35,18 +36,31 @@ XPCOMUtils.defineLazyGetter(this, "Brand
   const kBrandBundle = "chrome://branding/locale/brand.properties";
   return Services.strings.createBundle(kBrandBundle);
 });
 
 const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const kPrefCustomizationDebug = "browser.uiCustomization.debug";
 const kWidePanelItemClass = "panel-wide-item";
 
-var gModuleName = "[CustomizableWidgets]";
-#include logging.js
+XPCOMUtils.defineLazyGetter(this, "log", () => {
+  let scope = {};
+  Cu.import("resource://gre/modules/Console.jsm", scope);
+  let debug;
+  try {
+    debug = Services.prefs.getBoolPref(kPrefCustomizationDebug);
+  } catch (ex) {}
+  let consoleOptions = {
+    maxLogLevel: debug ? "all" : "log",
+    prefix: "CustomizableWidgets",
+  };
+  return new scope.ConsoleAPI(consoleOptions);
+});
+
+
 
 function setAttributes(aNode, aAttrs) {
   let doc = aNode.ownerDocument;
   for (let [name, value] of Iterator(aAttrs)) {
     if (!value) {
       if (aNode.hasAttribute(name))
         aNode.removeAttribute(name);
     } else {
@@ -210,26 +224,26 @@ const CustomizableWidgets = [
                 onHistoryVisit(uri, aEvent, item);
               });
               if (icon) {
                 let iconURL = "moz-anno:favicon:" + icon;
                 item.setAttribute("image", iconURL);
               }
               fragment.appendChild(item);
             } catch (e) {
-              ERROR("Error while showing history subview: " + e);
+              log.error("Error while showing history subview: " + e);
             }
           }
           items.appendChild(fragment);
         },
         handleError: function (aError) {
-          LOG("History view tried to show but had an error: " + aError);
+          log.debug("History view tried to show but had an error: " + aError);
         },
         handleCompletion: function (aReason) {
-          LOG("History view is being shown!");
+          log.debug("History view is being shown!");
         },
       });
 
       let recentlyClosedTabs = doc.getElementById("PanelUI-recentlyClosedTabs");
       while (recentlyClosedTabs.firstChild) {
         recentlyClosedTabs.removeChild(recentlyClosedTabs.firstChild);
       }
 
@@ -275,17 +289,17 @@ const CustomizableWidgets = [
       };
       let doc = aNode.ownerDocument;
       let recentlyClosedTabs = doc.getElementById("PanelUI-recentlyClosedTabs");
       let recentlyClosedWindows = doc.getElementById("PanelUI-recentlyClosedWindows");
       recentlyClosedTabs.addEventListener("click", onRecentlyClosedClick);
       recentlyClosedWindows.addEventListener("click", onRecentlyClosedClick);
     },
     onViewHiding: function(aEvent) {
-      LOG("History view is being hidden!");
+      log.debug("History view is being hidden!");
     }
   }, {
     id: "sync-button",
     label: "remotetabs-panelmenu.label",
     tooltiptext: "remotetabs-panelmenu.tooltiptext",
     type: "view",
     viewId: "PanelUI-remotetabs",
     defaultArea: CustomizableUI.AREA_PANEL,
@@ -535,21 +549,19 @@ const CustomizableWidgets = [
       }
     }
   }, {
     id: "developer-button",
     type: "view",
     viewId: "PanelUI-developer",
     shortcutId: "key_devToolboxMenuItem",
     tooltiptext: "developer-button.tooltiptext2",
-#ifdef MOZ_DEV_EDITION
-    defaultArea: CustomizableUI.AREA_NAVBAR,
-#else
-    defaultArea: CustomizableUI.AREA_PANEL,
-#endif
+    defaultArea: AppConstants.MOZ_DEV_EDITION ?
+                   CustomizableUI.AREA_NAVBAR :
+                   CustomizableUI.AREA_PANEL,
     onViewShowing: function(aEvent) {
       // Populate the subview with whatever menuitems are in the developer
       // menu. We skip menu elements, because the menu panel has no way
       // of dealing with those right now.
       let doc = aEvent.target.ownerDocument;
       let win = doc.defaultView;
 
       let menu = doc.getElementById("menuWebDeveloperPopup");
@@ -640,38 +652,16 @@ const CustomizableWidgets = [
       let win = aEvent.target &&
                 aEvent.target.ownerDocument &&
                 aEvent.target.ownerDocument.defaultView;
       if (win && typeof win.BrowserOpenAddonsMgr == "function") {
         win.BrowserOpenAddonsMgr();
       }
     }
   }, {
-    id: "preferences-button",
-    defaultArea: CustomizableUI.AREA_PANEL,
-#ifdef XP_WIN
-    label: "preferences-button.labelWin",
-    tooltiptext: "preferences-button.tooltipWin2",
-#else
-#ifdef XP_MACOSX
-    tooltiptext: "preferences-button.tooltiptext.withshortcut",
-    shortcutId: "key_preferencesCmdMac",
-#else
-    tooltiptext: "preferences-button.tooltiptext2",
-#endif
-#endif
-    onCommand: function(aEvent) {
-      let win = aEvent.target &&
-                aEvent.target.ownerDocument &&
-                aEvent.target.ownerDocument.defaultView;
-      if (win && typeof win.openPreferences == "function") {
-        win.openPreferences();
-      }
-    }
-  }, {
     id: "zoom-controls",
     type: "custom",
     tooltiptext: "zoom-controls.tooltiptext2",
     defaultArea: CustomizableUI.AREA_PANEL,
     onBuild: function(aDocument) {
       const kPanelId = "PanelUI-popup";
       let areaType = CustomizableUI.getAreaType(this.currentArea);
       let inPanel = areaType == CustomizableUI.TYPE_MENU_PANEL;
@@ -1138,16 +1128,39 @@ const CustomizableWidgets = [
     id: "email-link-button",
     tooltiptext: "email-link-button.tooltiptext3",
     onCommand: function(aEvent) {
       let win = aEvent.view;
       win.MailIntegration.sendLinkForBrowser(win.gBrowser.selectedBrowser)
     }
   }];
 
+let preferencesButton = {
+  id: "preferences-button",
+  defaultArea: CustomizableUI.AREA_PANEL,
+  onCommand: function(aEvent) {
+    let win = aEvent.target &&
+              aEvent.target.ownerDocument &&
+              aEvent.target.ownerDocument.defaultView;
+    if (win && typeof win.openPreferences == "function") {
+      win.openPreferences();
+    }
+  }
+};
+if (AppConstants.platform == "win") {
+  preferencesButton.label = "preferences-button.labelWin";
+  preferencesButton.tooltiptext = "preferences-button.tooltipWin2";
+} else if (AppConstants.platform == "macosx") {
+  preferencesButton.tooltiptext = "preferences-button.tooltiptext.withshortcut";
+  preferencesButton.shortcutId = "key_preferencesCmdMac";
+} else {
+  preferencesButton.tooltiptext = "preferences-button.tooltiptext2";
+}
+CustomizableWidgets.push(preferencesButton);
+
 if (Services.prefs.getBoolPref("privacy.panicButton.enabled")) {
   CustomizableWidgets.push({
     id: "panic-button",
     type: "view",
     viewId: "PanelUI-panicView",
     _sanitizer: null,
     _ensureSanitizer: function() {
       if (!this.sanitizer) {
@@ -1202,34 +1215,35 @@ if (Services.prefs.getBoolPref("privacy.
     },
     onViewHiding: function(aEvent) {
       let forgetButton = aEvent.target.querySelector("#PanelUI-panic-view-button");
       forgetButton.removeEventListener("command", this);
     },
   });
 }
 
-#ifdef E10S_TESTING_ONLY
-var e10sDisabled = false;
-#ifdef XP_MACOSX
-// On OS X, "Disable Hardware Acceleration" also disables OMTC and forces
-// a fallback to Basic Layers. This is incompatible with e10s.
-e10sDisabled |= Services.prefs.getBoolPref("layers.acceleration.disabled");
-#endif
+if (AppConstants.E10S_TESTING_ONLY) {
+  var e10sDisabled = false;
+
+  if (AppConstants.platform == "macosx") {
+    // On OS X, "Disable Hardware Acceleration" also disables OMTC and forces
+    // a fallback to Basic Layers. This is incompatible with e10s.
+    e10sDisabled |= Services.prefs.getBoolPref("layers.acceleration.disabled");
+  }
 
-if (Services.appinfo.browserTabsRemoteAutostart) {
-  CustomizableWidgets.push({
-    id: "e10s-button",
-    disabled: e10sDisabled,
-    defaultArea: CustomizableUI.AREA_PANEL,
-    onBuild: function(aDocument) {
-        node.setAttribute("label", CustomizableUI.getLocalizedProperty(this, "label"));
-        node.setAttribute("tooltiptext", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
-    },
-    onCommand: function(aEvent) {
-      let win = aEvent.view;
-      if (win && typeof win.OpenBrowserWindow == "function") {
-        win.OpenBrowserWindow({remote: false});
-      }
-    },
-  });
+  if (Services.appinfo.browserTabsRemoteAutostart) {
+    CustomizableWidgets.push({
+      id: "e10s-button",
+      disabled: e10sDisabled,
+      defaultArea: CustomizableUI.AREA_PANEL,
+      onBuild: function(aDocument) {
+          node.setAttribute("label", CustomizableUI.getLocalizedProperty(this, "label"));
+          node.setAttribute("tooltiptext", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
+      },
+      onCommand: function(aEvent) {
+        let win = aEvent.view;
+        if (win && typeof win.OpenBrowserWindow == "function") {
+          win.OpenBrowserWindow({remote: false});
+        }
+      },
+    });
+  }
 }
-#endif
--- a/browser/components/customizableui/CustomizeMode.jsm
+++ b/browser/components/customizableui/CustomizeMode.jsm
@@ -23,27 +23,39 @@ const kPanelItemContextMenu = "customiza
 const kPaletteItemContextMenu = "customizationPaletteItemContextMenu";
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/CustomizableUI.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/AddonManager.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "DragPositionManager",
                                   "resource:///modules/DragPositionManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
                                   "resource:///modules/BrowserUITelemetry.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
                                   "resource://gre/modules/LightweightThemeManager.jsm");
 
-
-var gModuleName = "[CustomizeMode]";
-#include logging.js
+let gDebug;
+XPCOMUtils.defineLazyGetter(this, "log", () => {
+  let scope = {};
+  Cu.import("resource://gre/modules/Console.jsm", scope);
+  let ConsoleAPI = scope.ConsoleAPI;
+  try {
+    gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug);
+  } catch (ex) {}
+  let consoleOptions = {
+    maxLogLevel: gDebug ? "all" : "log",
+    prefix: "CustomizeMode",
+  };
+  return new scope.ConsoleAPI(consoleOptions);
+});
 
 var gDisableAnimation = null;
 
 var gDraggingInToolbars;
 
 function CustomizeMode(aWindow) {
   if (gDisableAnimation === null) {
     gDisableAnimation = Services.prefs.getPrefType(kPrefCustomizationAnimation) == Ci.nsIPrefBranch.PREF_BOOL &&
@@ -60,20 +72,20 @@ function CustomizeMode(aWindow) {
   // to the user when in customizing mode.
   this.visiblePalette = this.document.getElementById(kPaletteId);
   this.paletteEmptyNotice = this.document.getElementById("customization-empty");
   this.tipPanel = this.document.getElementById("customization-tipPanel");
   if (Services.prefs.getCharPref("general.skins.selectedSkin") != "classic/1.0") {
     let lwthemeButton = this.document.getElementById("customization-lwtheme-button");
     lwthemeButton.setAttribute("hidden", "true");
   }
-#ifdef CAN_DRAW_IN_TITLEBAR
-  this._updateTitlebarButton();
-  Services.prefs.addObserver(kDrawInTitlebarPref, this, false);
-#endif
+  if (AppConstants.CAN_DRAW_IN_TITLEBAR) {
+    this._updateTitlebarButton();
+    Services.prefs.addObserver(kDrawInTitlebarPref, this, false);
+  }
   this.window.addEventListener("unload", this);
 };
 
 CustomizeMode.prototype = {
   _changed: false,
   _transitioning: false,
   window: null,
   document: null,
@@ -96,19 +108,19 @@ CustomizeMode.prototype = {
     return this.document.getElementById("PanelUI-contents");
   },
 
   get _handler() {
     return this.window.CustomizationHandler;
   },
 
   uninit: function() {
-#ifdef CAN_DRAW_IN_TITLEBAR
-    Services.prefs.removeObserver(kDrawInTitlebarPref, this);
-#endif
+    if (AppConstants.CAN_DRAW_IN_TITLEBAR) {
+      Services.prefs.removeObserver(kDrawInTitlebarPref, this);
+    }
   },
 
   toggle: function() {
     if (this._handler.isEnteringCustomizeMode || this._handler.isExitingCustomizeMode) {
       this._wantToBeInCustomizeMode = !this._wantToBeInCustomizeMode;
       return;
     }
     if (this._customizing) {
@@ -132,18 +144,18 @@ CustomizeMode.prototype = {
     this._wantToBeInCustomizeMode = true;
 
     if (this._customizing || this._handler.isEnteringCustomizeMode) {
       return;
     }
 
     // Exiting; want to re-enter once we've done that.
     if (this._handler.isExitingCustomizeMode) {
-      LOG("Attempted to enter while we're in the middle of exiting. " +
-          "We'll exit after we've entered");
+      log.debug("Attempted to enter while we're in the middle of exiting. " +
+                "We'll exit after we've entered");
       return;
     }
 
 
     // We don't need to switch to kAboutURI, or open a new tab at
     // kAboutURI if we're already on it.
     if (this.browser.selectedBrowser.currentURI.spec != kAboutURI) {
       this.window.switchToTabHavingURI(kAboutURI, true, {
@@ -157,17 +169,17 @@ CustomizeMode.prototype = {
 
     this._handler.isEnteringCustomizeMode = true;
 
     // Always disable the reset button at the start of customize mode, it'll be re-enabled
     // if necessary when we finish entering:
     let resetButton = this.document.getElementById("customization-reset-button");
     resetButton.setAttribute("disabled", "true");
 
-    Task.spawn(function() {
+    Task.spawn(function*() {
       // We shouldn't start customize mode until after browser-delayed-startup has finished:
       if (!this.window.gBrowserInit.delayedStartupFinished) {
         let delayedStartupDeferred = Promise.defer();
         let delayedStartupObserver = function(aSubject) {
           if (aSubject == this.window) {
             Services.obs.removeObserver(delayedStartupObserver, "browser-delayed-startup-finished");
             delayedStartupDeferred.resolve();
           }
@@ -304,17 +316,17 @@ CustomizeMode.prototype = {
       // It's possible that we didn't enter customize mode via the menu panel,
       // meaning we didn't kick off about:customizing preloading. If that's
       // the case, let's kick it off for the next time we load this mode.
       window.gCustomizationTabPreloader.ensurePreloading();
       if (!this._wantToBeInCustomizeMode) {
         this.exit();
       }
     }.bind(this)).then(null, function(e) {
-      ERROR("Error entering customize mode", e);
+      log.error("Error entering customize mode", e);
       // We should ensure this has been called, and calling it again doesn't hurt:
       window.PanelUI.endBatchUpdate();
       this._handler.isEnteringCustomizeMode = false;
       // Exit customize mode to ensure proper clean-up when entering failed.
       this.exit();
     }.bind(this));
   },
 
@@ -322,24 +334,24 @@ CustomizeMode.prototype = {
     this._wantToBeInCustomizeMode = false;
 
     if (!this._customizing || this._handler.isExitingCustomizeMode) {
       return;
     }
 
     // Entering; want to exit once we've done that.
     if (this._handler.isEnteringCustomizeMode) {
-      LOG("Attempted to exit while we're in the middle of entering. " +
-          "We'll exit after we've entered");
+      log.debug("Attempted to exit while we're in the middle of entering. " +
+                "We'll exit after we've entered");
       return;
     }
 
     if (this.resetting) {
-      LOG("Attempted to exit while we're resetting. " +
-          "We'll exit after resetting has finished.");
+      log.debug("Attempted to exit while we're resetting. " +
+                "We'll exit after resetting has finished.");
       return;
     }
 
     this.hideTip();
 
     this._handler.isExitingCustomizeMode = true;
 
     if (this._enableOutlinesTimeout) {
@@ -377,17 +389,17 @@ CustomizeMode.prototype = {
 
     // Disable the reset and undo reset buttons while transitioning:
     let resetButton = this.document.getElementById("customization-reset-button");
     let undoResetButton = this.document.getElementById("customization-undo-reset-button");
     undoResetButton.hidden = resetButton.disabled = true;
 
     this._transitioning = true;
 
-    Task.spawn(function() {
+    Task.spawn(function*() {
       yield this.depopulatePalette();
 
       yield this._doTransition(false);
       this.removeLWTStyling();
 
       Services.obs.removeObserver(this, "lightweight-theme-window-updated", false);
 
       let browser = document.getElementById("browser");
@@ -395,17 +407,17 @@ CustomizeMode.prototype = {
         let custBrowser = this.browser.selectedBrowser;
         if (custBrowser.canGoBack) {
           // If there's history to this tab, just go back.
           // Note that this throws an exception if the previous document has a
           // problematic URL (e.g. about:idontexist)
           try {
             custBrowser.goBack();
           } catch (ex) {
-            ERROR(ex);
+            log.error(ex);
           }
         } else {
           // If we can't go back, we're removing the about:customization tab.
           // We only do this if we're the top window for this window (so not
           // a dialog window, for example).
           if (window.getTopWin(true) == window) {
             let customizationTab = this.browser.selectedTab;
             if (this.browser.browsers.length == 1) {
@@ -479,17 +491,17 @@ CustomizeMode.prototype = {
       this._handler.isExitingCustomizeMode = false;
       CustomizableUI.dispatchToolboxEvent("aftercustomization", {}, window);
       CustomizableUI.notifyEndCustomizing(window);
 
       if (this._wantToBeInCustomizeMode) {
         this.enter();
       }
     }.bind(this)).then(null, function(e) {
-      ERROR("Error exiting customize mode", e);
+      log.error("Error exiting customize mode", e);
       // We should ensure this has been called, and calling it again doesn't hurt:
       window.PanelUI.endBatchUpdate();
       this._handler.isExitingCustomizeMode = false;
     }.bind(this));
   },
 
   /**
    * The customize mode transition has 4 phases when entering:
@@ -573,25 +585,25 @@ CustomizeMode.prototype = {
 
     let deck = this.document.getElementById("tab-view-deck");
     let headerImageRef = this._getHeaderImageRef(aData);
     docElement.setAttribute("customization-lwtheme", "true");
 
     let toolboxRect = this.window.gNavToolbox.getBoundingClientRect();
     let height = toolboxRect.bottom;
 
-#ifdef XP_MACOSX
-    let drawingInTitlebar = !docElement.hasAttribute("drawtitle");
-    let titlebar = this.document.getElementById("titlebar");
-    if (drawingInTitlebar) {
-      titlebar.style.backgroundImage = headerImageRef;
-    } else {
-      titlebar.style.removeProperty("background-image");
+    if (AppConstants.platform == "macosx") {
+      let drawingInTitlebar = !docElement.hasAttribute("drawtitle");
+      let titlebar = this.document.getElementById("titlebar");
+      if (drawingInTitlebar) {
+        titlebar.style.backgroundImage = headerImageRef;
+      } else {
+        titlebar.style.removeProperty("background-image");
+      }
     }
-#endif
 
     let limitedBG = "-moz-image-rect(" + headerImageRef + ", 0, 100%, " +
                     height + ", 0)";
 
     let ridgeStart = height - 1;
     let ridgeCenter = (ridgeStart + 1) + "px";
     let ridgeEnd = (ridgeStart + 2) + "px";
     ridgeStart = ridgeStart + "px";
@@ -606,21 +618,19 @@ CustomizeMode.prototype = {
     deck.style.backgroundImage = ridge + ", " + limitedBG;
 
     /* Remove the background styles from the <window> so we can style it instead. */
     docElement.style.removeProperty("background-image");
     docElement.style.removeProperty("background-color");
   },
 
   removeLWTStyling: function() {
-#ifdef XP_MACOSX
-    let affectedNodes = ["tab-view-deck", "titlebar"];
-#else
-    let affectedNodes = ["tab-view-deck"];
-#endif
+    let affectedNodes = AppConstants.platform == "macosx" ?
+                          ["tab-view-deck", "titlebar"] :
+                          ["tab-view-deck"];
     for (let id of affectedNodes) {
       let node = this.document.getElementById(id);
       node.style.removeProperty("background-image");
     }
     let docElement = this.document.documentElement;
     docElement.removeAttribute("customization-lwtheme");
     let data = docElement._lightweightTheme.getData();
     if (data && data.headerURL) {
@@ -750,42 +760,42 @@ CustomizeMode.prototype = {
         }
         fragment.appendChild(paletteItem);
       }
 
       this.visiblePalette.appendChild(fragment);
       this._stowedPalette = this.window.gNavToolbox.palette;
       this.window.gNavToolbox.palette = this.visiblePalette;
     } catch (ex) {
-      ERROR(ex);
+      log.error(ex);
     }
   },
 
   //XXXunf Maybe this should use -moz-element instead of wrapping the node?
   //       Would ensure no weird interactions/event handling from original node,
   //       and makes it possible to put this in a lazy-loaded iframe/real tab
   //       while still getting rid of the need for overlays.
   makePaletteItem: function(aWidget, aPlace) {
     let widgetNode = aWidget.forWindow(this.window).node;
     if (!widgetNode) {
-      ERROR("Widget with id " + aWidget.id + " does not return a valid node");
+      log.error("Widget with id " + aWidget.id + " does not return a valid node");
       return null;
     }
     // Do not build a palette item for hidden widgets; there's not much to show.
     if (widgetNode.hidden) {
       return null;
     }
 
     let wrapper = this.createOrUpdateWrapper(widgetNode, aPlace);
     wrapper.appendChild(widgetNode);
     return wrapper;
   },
 
   depopulatePalette: function() {
-    return Task.spawn(function() {
+    return Task.spawn(function*() {
       this.visiblePalette.hidden = true;
       let paletteChild = this.visiblePalette.firstChild;
       let nextChild;
       while (paletteChild) {
         nextChild = paletteChild.nextElementSibling;
         let provider = CustomizableUI.getWidget(paletteChild.id).provider;
         if (provider == CustomizableUI.PROVIDER_XUL) {
           let unwrappedPaletteItem =
@@ -801,17 +811,17 @@ CustomizeMode.prototype = {
         } else if (provider == CustomizableUI.PROVIDER_SPECIAL) {
           this.visiblePalette.removeChild(paletteChild);
         }
 
         paletteChild = nextChild;
       }
       this.visiblePalette.hidden = false;
       this.window.gNavToolbox.palette = this._stowedPalette;
-    }.bind(this)).then(null, ERROR);
+    }.bind(this)).then(null, log.error);
   },
 
   isCustomizableItem: function(aNode) {
     return aNode.localName == "toolbarbutton" ||
            aNode.localName == "toolbaritem" ||
            aNode.localName == "toolbarseparator" ||
            aNode.localName == "toolbarspring" ||
            aNode.localName == "toolbarspacer";
@@ -954,17 +964,17 @@ CustomizeMode.prototype = {
     }
     aWrapper.removeEventListener("mousedown", this);
     aWrapper.removeEventListener("mouseup", this);
 
     let place = aWrapper.getAttribute("place");
 
     let toolbarItem = aWrapper.firstChild;
     if (!toolbarItem) {
-      ERROR("no toolbarItem child for " + aWrapper.tagName + "#" + aWrapper.id);
+      log.error("no toolbarItem child for " + aWrapper.tagName + "#" + aWrapper.id);
       aWrapper.remove();
       return null;
     }
 
     if (aWrapper.hasAttribute("itemobserves")) {
       toolbarItem.setAttribute("observes", aWrapper.getAttribute("itemobserves"));
     }
 
@@ -1003,17 +1013,17 @@ CustomizeMode.prototype = {
     let target = CustomizableUI.getCustomizeTargetForArea(aArea, this.window);
     if (!target || this.areas.has(target)) {
       return null;
     }
 
     this._addDragHandlers(target);
     for (let child of target.children) {
       if (this.isCustomizableItem(child) && !this.isWrappedToolbarItem(child)) {
-        yield this.deferredWrapToolbarItem(child, CustomizableUI.getPlaceForItem(child)).then(null, ERROR);
+        yield this.deferredWrapToolbarItem(child, CustomizableUI.getPlaceForItem(child)).then(null, log.error);
       }
     }
     this.areas.add(target);
     return target;
   },
 
   _wrapToolbarItemSync: function(aArea) {
     let target = CustomizableUI.getCustomizeTargetForArea(aArea, this.window);
@@ -1024,17 +1034,17 @@ CustomizeMode.prototype = {
     this._addDragHandlers(target);
     try {
       for (let child of target.children) {
         if (this.isCustomizableItem(child) && !this.isWrappedToolbarItem(child)) {
           this.wrapToolbarItem(child, CustomizableUI.getPlaceForItem(child));
         }
       }
     } catch (ex) {
-      ERROR(ex, ex.stack);
+      log.error(ex, ex.stack);
     }
 
     this.areas.add(target);
     return target;
   },
 
   _wrapToolbarItems: function*() {
     for (let area of CustomizableUI.areas) {
@@ -1070,27 +1080,27 @@ CustomizeMode.prototype = {
     for (let toolbarItem of target.children) {
       if (this.isWrappedToolbarItem(toolbarItem)) {
         this.unwrapToolbarItem(toolbarItem);
       }
     }
   },
 
   _unwrapToolbarItems: function() {
-    return Task.spawn(function() {
+    return Task.spawn(function*() {
       for (let target of this.areas) {
         for (let toolbarItem of target.children) {
           if (this.isWrappedToolbarItem(toolbarItem)) {
             yield this.deferredUnwrapToolbarItem(toolbarItem);
           }
         }
         this._removeDragHandlers(target);
       }
       this.areas.clear();
-    }.bind(this)).then(null, ERROR);
+    }.bind(this)).then(null, log.error);
   },
 
   _removeExtraToolbarsIfEmpty: function() {
     let toolbox = this.window.gNavToolbox;
     for (let child of toolbox.children) {
       if (child.hasAttribute("customindex")) {
         let placements = CustomizableUI.getWidgetIdsInArea(child.id);
         if (!placements.length) {
@@ -1114,17 +1124,17 @@ CustomizeMode.prototype = {
   },
 
   reset: function() {
     this.resetting = true;
     // Disable the reset button temporarily while resetting:
     let btn = this.document.getElementById("customization-reset-button");
     BrowserUITelemetry.countCustomizationEvent("reset");
     btn.disabled = true;
-    return Task.spawn(function() {
+    return Task.spawn(function*() {
       this._removePanelCustomizationPlaceholders();
       yield this.depopulatePalette();
       yield this._unwrapToolbarItems();
 
       CustomizableUI.reset();
 
       yield this._wrapToolbarItems();
       this.populatePalette();
@@ -1134,39 +1144,39 @@ CustomizeMode.prototype = {
       this._updateResetButton();
       this._updateUndoResetButton();
       this._updateEmptyPaletteNotice();
       this._showPanelCustomizationPlaceholders();
       this.resetting = false;
       if (!this._wantToBeInCustomizeMode) {
         this.exit();
       }
-    }.bind(this)).then(null, ERROR);
+    }.bind(this)).then(null, log.error);
   },
 
   undoReset: function() {
     this.resetting = true;
 
-    return Task.spawn(function() {
+    return Task.spawn(function*() {
       this._removePanelCustomizationPlaceholders();
       yield this.depopulatePalette();
       yield this._unwrapToolbarItems();
 
       CustomizableUI.undoReset();
 
       yield this._wrapToolbarItems();
       this.populatePalette();
 
       this.persistCurrentSets(true);
 
       this._updateResetButton();
       this._updateUndoResetButton();
       this._updateEmptyPaletteNotice();
       this.resetting = false;
-    }.bind(this)).then(null, ERROR);
+    }.bind(this)).then(null, log.error);
   },
 
   _onToolbarVisibilityChange: function(aEvent) {
     let toolbar = aEvent.target;
     if (aEvent.detail.visible && toolbar.getAttribute("customizable") == "true") {
       toolbar.setAttribute("customizing", "true");
     } else {
       toolbar.removeAttribute("customizing");
@@ -1479,53 +1489,57 @@ CustomizeMode.prototype = {
     }
   },
 
   observe: function(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "nsPref:changed":
         this._updateResetButton();
         this._updateUndoResetButton();
-#ifdef CAN_DRAW_IN_TITLEBAR
-        this._updateTitlebarButton();
-#endif
+        if (AppConstants.CAN_DRAW_IN_TITLEBAR) {
+          this._updateTitlebarButton();
+        }
         break;
       case "lightweight-theme-window-updated":
         if (aSubject == this.window) {
           aData = JSON.parse(aData);
           if (!aData) {
             this.removeLWTStyling();
           } else {
             this.updateLWTStyling(aData);
           }
         }
         break;
     }
   },
 
-#ifdef CAN_DRAW_IN_TITLEBAR
   _updateTitlebarButton: function() {
+    if (!AppConstants.CAN_DRAW_IN_TITLEBAR) {
+      return;
+    }
     let drawInTitlebar = true;
     try {
       drawInTitlebar = Services.prefs.getBoolPref(kDrawInTitlebarPref);
     } catch (ex) { }
     let button = this.document.getElementById("customization-titlebar-visibility-button");
     // Drawing in the titlebar means 'hiding' the titlebar:
     if (drawInTitlebar) {
       button.removeAttribute("checked");
     } else {
       button.setAttribute("checked", "true");
     }
   },
 
   toggleTitlebar: function(aShouldShowTitlebar) {
+    if (!AppConstants.CAN_DRAW_IN_TITLEBAR) {
+      return;
+    }
     // Drawing in the titlebar means not showing the titlebar, hence the negation:
     Services.prefs.setBoolPref(kDrawInTitlebarPref, !aShouldShowTitlebar);
   },
-#endif
 
   _onDragStart: function(aEvent) {
     __dumpDragData(aEvent);
     let item = aEvent.target;
     while (item && item.localName != "toolbarpaletteitem") {
       if (item.localName == "toolbar") {
         return;
       }
@@ -1718,17 +1732,17 @@ CustomizeMode.prototype = {
     }
 
     this._cancelDragActive(this._dragOverItem, null, true);
     this._removePanelCustomizationPlaceholders();
 
     try {
       this._applyDrop(aEvent, targetArea, originArea, draggedItemId, targetNode);
     } catch (ex) {
-      ERROR(ex, ex.stack);
+      log.error(ex, ex.stack);
     }
 
     this._showPanelCustomizationPlaceholders();
   },
 
   _applyDrop: function(aEvent, aTargetArea, aOriginArea, aDraggedItemId, aTargetNode) {
     let document = aEvent.target.ownerDocument;
     let draggedItem = document.getElementById(aDraggedItemId);
@@ -1825,17 +1839,17 @@ CustomizeMode.prototype = {
     }
     if (itemForPlacement && !itemForPlacement.classList.contains(kPlaceholderClass)) {
       let targetNodeId = (itemForPlacement.nodeName == "toolbarpaletteitem") ?
                             itemForPlacement.firstChild && itemForPlacement.firstChild.id :
                             itemForPlacement.id;
       placement = CustomizableUI.getPlacementOfWidget(targetNodeId);
     }
     if (!placement) {
-      LOG("Could not get a position for " + aTargetNode.nodeName + "#" + aTargetNode.id + "." + aTargetNode.className);
+      log.debug("Could not get a position for " + aTargetNode.nodeName + "#" + aTargetNode.id + "." + aTargetNode.className);
     }
     let position = placement ? placement.position : null;
 
     // Is the target area the same as the origin? Since we've already handled
     // the possibility that the target is the customization palette, we know
     // that the widget is moving within a customizable area.
     if (aTargetArea == aOriginArea) {
       CustomizableUI.moveWidgetWithinArea(aDraggedItemId, position);
@@ -2146,31 +2160,31 @@ CustomizeMode.prototype = {
       }
       // Find the closest node:
       targetNode = positionManager.find(aAreaElement, dragX, dragY, aDraggedItemId);
     }
     return targetNode || aEvent.target;
   },
 
   _onMouseDown: function(aEvent) {
-    LOG("_onMouseDown");
+    log.debug("_onMouseDown");
     if (aEvent.button != 0) {
       return;
     }
     let doc = aEvent.target.ownerDocument;
     doc.documentElement.setAttribute("customizing-movingItem", true);
     let item = this._getWrapper(aEvent.target);
     if (item && !item.classList.contains(kPlaceholderClass) &&
         item.getAttribute("removable") == "true") {
       item.setAttribute("mousedown", "true");
     }
   },
 
   _onMouseUp: function(aEvent) {
-    LOG("_onMouseUp");
+    log.debug("_onMouseUp");
     if (aEvent.button != 0) {
       return;
     }
     let doc = aEvent.target.ownerDocument;
     doc.documentElement.removeAttribute("customizing-movingItem");
     let item = this._getWrapper(aEvent.target);
     if (item) {
       item.removeAttribute("mousedown");
@@ -2279,14 +2293,14 @@ function __dumpDragData(aEvent, caller) 
     }
   }
   for (let prop in aEvent.dataTransfer) {
     if (typeof aEvent.dataTransfer[prop] != "function") {
       str += "  dataTransfer[" + prop + "]: " + aEvent.dataTransfer[prop] + "\n";
     }
   }
   str += "}";
-  LOG(str);
+  log.debug(str);
 }
 
 function dispatchFunction(aFunc) {
   Services.tm.currentThread.dispatch(aFunc, Ci.nsIThread.DISPATCH_NORMAL);
 }
--- a/browser/components/customizableui/PanelWideWidgetTracker.jsm
+++ b/browser/components/customizableui/PanelWideWidgetTracker.jsm
@@ -6,19 +6,16 @@
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 this.EXPORTED_SYMBOLS = ["PanelWideWidgetTracker"];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
   "resource:///modules/CustomizableUI.jsm");
 
-var gModuleName = "[PanelWideWidgetTracker]";
-#include logging.js
-
 var gPanel = CustomizableUI.AREA_PANEL;
 // We keep track of the widget placements for the panel locally:
 var gPanelPlacements = [];
 
 // All the wide widgets we know of:
 var gWideWidgets = new Set();
 // All the widgets we know of:
 var gSeenWidgets = new Set();
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -223,17 +223,17 @@ const PanelUI = {
    *        mode will handle calling beginBatchUpdate and endBatchUpdate.
    *
    * @return a Promise that resolves once the panel is ready to roll.
    */
   ensureReady: function(aCustomizing=false) {
     if (this._readyPromise) {
       return this._readyPromise;
     }
-    this._readyPromise = Task.spawn(function() {
+    this._readyPromise = Task.spawn(function*() {
       if (!this._initialized) {
         let delayedStartupDeferred = Promise.defer();
         let delayedStartupObserver = (aSubject, aTopic, aData) => {
           if (aSubject == window) {
             Services.obs.removeObserver(delayedStartupObserver, "browser-delayed-startup-finished");
             delayedStartupDeferred.resolve();
           }
         };
deleted file mode 100644
--- a/browser/components/customizableui/logging.js
+++ /dev/null
@@ -1,31 +0,0 @@
-#if 0
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#endif
-
-XPCOMUtils.defineLazyModuleGetter(this, "console",
-  "resource://gre/modules/Console.jsm");
-
-var gDebug = false;
-try {
-  gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug);
-} catch (e) {}
-
-function LOG(...args) {
-  if (gDebug) {
-    args.unshift(gModuleName);
-    console.log.apply(console, args);
-  }
-}
-
-function ERROR(...args) {
-  args.unshift(gModuleName);
-  console.error.apply(console, args);
-}
-
-function INFO(...args) {
-  args.unshift(gModuleName);
-  console.info.apply(console, args);
-}
-
--- a/browser/components/customizableui/moz.build
+++ b/browser/components/customizableui/moz.build
@@ -6,27 +6,21 @@
 
 DIRS += [
     'content',
 ]
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
 EXTRA_JS_MODULES += [
+    'CustomizableUI.jsm',
+    'CustomizableWidgets.jsm',
+    'CustomizeMode.jsm',
     'DragPositionManager.jsm',
+    'PanelWideWidgetTracker.jsm',
     'ScrollbarSampler.jsm',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
     DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'):
-    DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1
-
-EXTRA_PP_JS_MODULES += [
-    'CustomizableUI.jsm',
-    'CustomizableWidgets.jsm',
-    'CustomizeMode.jsm',
-    'PanelWideWidgetTracker.jsm',
-]
-
 with Files('**'):
     BUG_COMPONENT = ('Firefox', 'Toolbars and Customization')
--- a/browser/components/customizableui/test/browser_1007336_lwthemes_in_customize_mode.js
+++ b/browser/components/customizableui/test/browser_1007336_lwthemes_in_customize_mode.js
@@ -2,17 +2,17 @@
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const DEFAULT_THEME_ID = "{972ce4c6-7e08-4474-a285-3208198ce6fd}";
 const {LightweightThemeManager} = Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", {});
 
-add_task(function () {
+add_task(function* () {
   Services.prefs.clearUserPref("lightweightThemes.usedThemes");
   Services.prefs.clearUserPref("lightweightThemes.recommendedThemes");
   LightweightThemeManager.clearBuiltInThemes();
 
   yield startCustomizing();
 
   let themesButton = document.getElementById("customization-lwtheme-button");
   let popup = document.getElementById("customization-lwtheme-menu");
@@ -49,14 +49,14 @@ add_task(function () {
   is(header.nextSibling.nextSibling.nextSibling, recommendedHeader,
      "There should be two themes in the 'My Themes' section");
 
   let defaultTheme = header.nextSibling;
   defaultTheme.doCommand();
   is(Services.prefs.getCharPref("lightweightThemes.selectedThemeID"), "", "No lwtheme should be selected");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield endCustomizing();
 
   Services.prefs.clearUserPref("lightweightThemes.usedThemes");
   Services.prefs.clearUserPref("lightweightThemes.recommendedThemes");
-})
\ No newline at end of file
+});
--- a/browser/components/customizableui/test/browser_1058573_showToolbarsDropdown.js
+++ b/browser/components/customizableui/test/browser_1058573_showToolbarsDropdown.js
@@ -1,25 +1,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-add_task(function() {
+add_task(function*() {
   info("Check that toggleable toolbars dropdown in always shown");
 
   info("Remove all possible custom toolbars");
   yield removeCustomToolbars();
 
   info("Enter customization mode");
   yield startCustomizing();
 
   let toolbarsToggle = document.getElementById("customization-toolbar-visibility-button");
   ok(toolbarsToggle, "The toolbars toggle dropdown exists");
   ok(!toolbarsToggle.hasAttribute("hidden"),
      "The toolbars toggle dropdown is displayed");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   info("Exit customization mode");
   yield endCustomizing();
 });
--- a/browser/components/customizableui/test/browser_1087303_button_fullscreen.js
+++ b/browser/components/customizableui/test/browser_1087303_button_fullscreen.js
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-add_task(function() {
+add_task(function*() {
   info("Check fullscreen button existence and functionality");
 
   yield PanelUI.show();
 
   let fullscreenButton = document.getElementById("fullscreen-button");
   ok(fullscreenButton, "Fullscreen button appears in Panel Menu");
 
   let fullscreenPromise = promiseFullscreenChange();
--- a/browser/components/customizableui/test/browser_1087303_button_preferences.js
+++ b/browser/components/customizableui/test/browser_1087303_button_preferences.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var newTab = null;
 
-add_task(function() {
+add_task(function*() {
   info("Check preferences button existence and functionality");
 
   yield PanelUI.show();
   info("Menu panel was opened");
 
   let preferencesButton = document.getElementById("preferences-button");
   ok(preferencesButton, "Preferences button exists in Panel Menu");
   preferencesButton.click();
--- a/browser/components/customizableui/test/browser_873501_handle_specials.js
+++ b/browser/components/customizableui/test/browser_873501_handle_specials.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 const kToolbarName = "test-specials-toolbar";
 
 registerCleanupFunction(removeCustomToolbars);
 
 // Add a toolbar with two springs and the downloads button.
-add_task(function addToolbarWith2SpringsAndDownloadsButton() {
+add_task(function* addToolbarWith2SpringsAndDownloadsButton() {
   // Create the toolbar with a single spring:
   createToolbarWithPlacements(kToolbarName, ["spring"]);
   ok(document.getElementById(kToolbarName), "Toolbar should be created.");
 
   // Check it's there with a generated ID:
   assertAreaPlacements(kToolbarName, [/customizableui-special-spring\d+/]);
   let [springId] = getAreaWidgetIds(kToolbarName);
 
@@ -28,17 +28,17 @@ add_task(function addToolbarWith2Springs
 
   // Try moving the downloads button to this new toolbar, between the two springs:
   CustomizableUI.addWidgetToArea("downloads-button", kToolbarName, 1);
   assertAreaPlacements(kToolbarName, [springId, "downloads-button", spring2Id]);
   yield removeCustomToolbars();
 });
 
 // Add separators around the downloads button.
-add_task(function addSeparatorsAroundDownloadsButton() {
+add_task(function* addSeparatorsAroundDownloadsButton() {
   createToolbarWithPlacements(kToolbarName, ["separator"]);
   ok(document.getElementById(kToolbarName), "Toolbar should be created.");
 
   // Check it's there with a generated ID:
   assertAreaPlacements(kToolbarName, [/customizableui-special-separator\d+/]);
   let [separatorId] = getAreaWidgetIds(kToolbarName);
 
   CustomizableUI.addWidgetToArea("separator", kToolbarName);
@@ -49,17 +49,17 @@ add_task(function addSeparatorsAroundDow
   isnot(separatorId, separator2Id, "Separator ids shouldn't be equal.");
 
   CustomizableUI.addWidgetToArea("downloads-button", kToolbarName, 1);
   assertAreaPlacements(kToolbarName, [separatorId, "downloads-button", separator2Id]);
   yield removeCustomToolbars();
 });
 
 // Add spacers around the downloads button.
-add_task(function addSpacersAroundDownloadsButton() {
+add_task(function* addSpacersAroundDownloadsButton() {
   createToolbarWithPlacements(kToolbarName, ["spacer"]);
   ok(document.getElementById(kToolbarName), "Toolbar should be created.");
 
   // Check it's there with a generated ID:
   assertAreaPlacements(kToolbarName, [/customizableui-special-spacer\d+/]);
   let [spacerId] = getAreaWidgetIds(kToolbarName);
 
   CustomizableUI.addWidgetToArea("spacer", kToolbarName);
@@ -69,11 +69,11 @@ add_task(function addSpacersAroundDownlo
 
   isnot(spacerId, spacer2Id, "Spacer ids shouldn't be equal.");
 
   CustomizableUI.addWidgetToArea("downloads-button", kToolbarName, 1);
   assertAreaPlacements(kToolbarName, [spacerId, "downloads-button", spacer2Id]);
   yield removeCustomToolbars();
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js
+++ b/browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js
@@ -149,17 +149,17 @@ function createXULButtonForWindow(win) {
 
 function removeXULButtonForWindow(win) {
   win.gNavToolbox.palette.querySelector(`#${kXULWidgetId}`).remove();
 }
 
 var otherWin;
 
 // Moving widgets in two windows, one with customize mode and one without, should work.
-add_task(function MoveWidgetsInTwoWindows() {
+add_task(function* MoveWidgetsInTwoWindows() {
   yield startCustomizing();
   otherWin = yield openAndLoadWindow(null, true);
   yield otherWin.PanelUI.ensureReady();
   // Create the XUL button to use in the test in both windows.
   createXULButtonForWindow(window);
   createXULButtonForWindow(otherWin);
   ok(CustomizableUI.inDefaultState, "Should start in default state");
 
@@ -175,11 +175,11 @@ add_task(function MoveWidgetsInTwoWindow
     }
   }
   yield promiseWindowClosed(otherWin);
   otherWin = null;
   yield endCustomizing();
   removeXULButtonForWindow(window);
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js
+++ b/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js
@@ -3,34 +3,34 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const kTestWidget1 = "test-customize-mode-create-destroy1";
 const kTestWidget2 = "test-customize-mode-create-destroy2";
 
 // Creating and destroying a widget should correctly wrap/unwrap stuff
-add_task(function testWrapUnwrap() {
+add_task(function* testWrapUnwrap() {
   yield startCustomizing();
   CustomizableUI.createWidget({id: kTestWidget1, label: 'Pretty label', tooltiptext: 'Pretty tooltip'});
   let elem = document.getElementById(kTestWidget1);
   let wrapper = document.getElementById("wrapper-" + kTestWidget1);
   ok(elem, "There should be an item");
   ok(wrapper, "There should be a wrapper");
   is(wrapper.firstChild.id, kTestWidget1, "Wrapper should have test widget");
   is(wrapper.parentNode.id, "customization-palette", "Wrapper should be in palette");
   CustomizableUI.destroyWidget(kTestWidget1);
   wrapper = document.getElementById("wrapper-" + kTestWidget1);
   ok(!wrapper, "There should be a wrapper");
   let item = document.getElementById(kTestWidget1);
   ok(!item, "There should no longer be an item");
 });
 
 // Creating and destroying a widget should correctly deal with panel placeholders
-add_task(function testPanelPlaceholders() {
+add_task(function* testPanelPlaceholders() {
   let panel = document.getElementById(CustomizableUI.AREA_PANEL);
   // The value of expectedPlaceholders depends on the default palette layout.
   // Bug 1229236 is for these tests to be smarter so the test doesn't need to
   // change when the default placements change.
   let expectedPlaceholders = 1 + (isInDevEdition() ? 1 : 0);
   is(panel.querySelectorAll(".panel-customization-placeholder").length, expectedPlaceholders, "The number of placeholders should be correct.");
   CustomizableUI.createWidget({id: kTestWidget2, label: 'Pretty label', tooltiptext: 'Pretty tooltip', defaultArea: CustomizableUI.AREA_PANEL});
   let elem = document.getElementById(kTestWidget2);
@@ -44,17 +44,17 @@ add_task(function testPanelPlaceholders(
   CustomizableUI.destroyWidget(kTestWidget2);
   wrapper = document.getElementById("wrapper-" + kTestWidget2);
   ok(!wrapper, "There should be a wrapper");
   let item = document.getElementById(kTestWidget2);
   ok(!item, "There should no longer be an item");
   yield endCustomizing();
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield endCustomizing();
   try {
     CustomizableUI.destroyWidget(kTestWidget1);
   } catch (ex) {}
   try {
     CustomizableUI.destroyWidget(kTestWidget2);
   } catch (ex) {}
   yield resetCustomization();
--- a/browser/components/customizableui/test/browser_877006_missing_view.js
+++ b/browser/components/customizableui/test/browser_877006_missing_view.js
@@ -31,11 +31,11 @@ add_task(function testAddbrokenViewWidge
     CustomizableUI.destroyWidget(kWidgetId);
   } catch (ex) {
     Cu.reportError(ex);
     noError = false;
   }
   ok(noError, "Should not throw an exception trying to remove the broken view widget.");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_877178_unregisterArea.js
+++ b/browser/components/customizableui/test/browser_877178_unregisterArea.js
@@ -40,11 +40,11 @@ add_task(function checkRegisteringAndUnr
                         kButtonId,
                         /customizableui-special-spring\d+/]);
   ok(!CustomizableUI.inDefaultState, "With a new toolbar it is no longer in a default state.");
   removeCustomToolbars(); // Will call unregisterArea for us
   ok(CustomizableUI.inDefaultState, "When the toolbar is unregistered, " +
      "everything will return to the default state.");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_877447_skip_missing_ids.js
+++ b/browser/components/customizableui/test/browser_877447_skip_missing_ids.js
@@ -15,11 +15,11 @@ add_task(function skipMissingIDS() {
   ok(!CustomizableUI.inDefaultState, "Should no longer be in the default state.");
   is(btn.parentNode.parentNode.id, CustomizableUI.AREA_NAVBAR, "Button should be in navbar");
   btn.remove();
   is(btn.parentNode, null, "Button is no longer in the navbar");
   ok(CustomizableUI.inDefaultState, "Should be back in the default state, " +
                                     "despite unknown button ID in placements.");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_878452_drag_to_panel.js
+++ b/browser/components/customizableui/test/browser_878452_drag_to_panel.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Dragging an item from the palette to another button in the panel should work.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let btn = document.getElementById("feed-button");
   let panel = document.getElementById(CustomizableUI.AREA_PANEL);
   let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
 
   let lastButtonIndex = placements.length - 1;
   let lastButton = placements[lastButtonIndex];
   let placementsAfterInsert = placements.slice(0, lastButtonIndex).concat(["feed-button", lastButton]);
@@ -19,33 +19,33 @@ add_task(function() {
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   let palette = document.getElementById("customization-palette");
   simulateItemDrag(btn, palette);
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
 // Dragging an item from the palette to the panel itself should also work.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let btn = document.getElementById("feed-button");
   let panel = document.getElementById(CustomizableUI.AREA_PANEL);
   let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
 
   let placementsAfterAppend = placements.concat(["feed-button"]);
   simulateItemDrag(btn, panel);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   let palette = document.getElementById("customization-palette");
   simulateItemDrag(btn, palette);
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
 // Dragging an item from the palette to an empty panel should also work.
-add_task(function() {
+add_task(function*() {
   let widgetIds = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
   while (widgetIds.length) {
     CustomizableUI.removeWidgetFromArea(widgetIds.shift());
   }
   yield startCustomizing();
   let btn = document.getElementById("feed-button");
   let panel = document.getElementById(CustomizableUI.AREA_PANEL);
 
@@ -55,12 +55,12 @@ add_task(function() {
   simulateItemDrag(btn, panel);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   let palette = document.getElementById("customization-palette");
   simulateItemDrag(btn, palette);
   assertAreaPlacements(panel.id, []);
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield endCustomizing();
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_880164_customization_context_menus.js
+++ b/browser/components/customizableui/test/browser_880164_customization_context_menus.js
@@ -5,17 +5,17 @@
 "use strict";
 
 requestLongerTimeout(2);
 
 const isOSX = (Services.appinfo.OS === "Darwin");
 
 // Right-click on the home button should
 // show a context menu with options to move it.
-add_task(function() {
+add_task(function*() {
   let contextMenu = document.getElementById("toolbar-context-menu");
   let shownPromise = popupShown(contextMenu);
   let homeButton = document.getElementById("home-button");
   EventUtils.synthesizeMouse(homeButton, 2, 2, {type: "contextmenu", button: 2 });
   yield shownPromise;
 
   let expectedEntries = [
     [".customize-context-moveToPanel", true],
@@ -35,17 +35,17 @@ add_task(function() {
   let hiddenPromise = popupHidden(contextMenu);
   contextMenu.hidePopup();
   yield hiddenPromise;
 });
 
 // Right-click on an empty bit of tabstrip should
 // show a context menu without options to move it,
 // but with tab-specific options instead.
-add_task(function() {
+add_task(function*() {
   // ensure there are tabs to reload/bookmark:
   let extraTab = gBrowser.selectedTab = gBrowser.addTab();
   yield promiseTabLoadEvent(extraTab, "http://example.com/");
   let contextMenu = document.getElementById("toolbar-context-menu");
   let shownPromise = popupShown(contextMenu);
   let tabstrip = document.getElementById("tabbrowser-tabs");
   let rect = tabstrip.getBoundingClientRect();
   EventUtils.synthesizeMouse(tabstrip, rect.width - 2, 2, {type: "contextmenu", button: 2 });
@@ -73,17 +73,17 @@ add_task(function() {
   contextMenu.hidePopup();
   yield hiddenPromise;
   gBrowser.removeTab(extraTab);
 });
 
 // Right-click on an empty bit of extra toolbar should
 // show a context menu with moving options disabled,
 // and a toggle option for the extra toolbar
-add_task(function() {
+add_task(function*() {
   let contextMenu = document.getElementById("toolbar-context-menu");
   let shownPromise = popupShown(contextMenu);
   let toolbar = createToolbarWithPlacements("880164_empty_toolbar", []);
   toolbar.setAttribute("context", "toolbar-context-menu");
   toolbar.setAttribute("toolbarname", "Fancy Toolbar for Context Menu");
   EventUtils.synthesizeMouseAtCenter(toolbar, {type: "contextmenu", button: 2 });
   yield shownPromise;
 
@@ -107,17 +107,17 @@ add_task(function() {
   contextMenu.hidePopup();
   yield hiddenPromise;
   removeCustomToolbars();
 });
 
 
 // Right-click on the urlbar-container should
 // show a context menu with disabled options to move it.
-add_task(function() {
+add_task(function*() {
   let contextMenu = document.getElementById("toolbar-context-menu");
   let shownPromise = popupShown(contextMenu);
   let urlBarContainer = document.getElementById("urlbar-container");
   // Need to make sure not to click within an edit field.
   let urlbarRect = urlBarContainer.getBoundingClientRect();
   EventUtils.synthesizeMouse(urlBarContainer, 100, 1, {type: "contextmenu", button: 2 });
   yield shownPromise;
 
@@ -138,17 +138,17 @@ add_task(function() {
 
   let hiddenPromise = popupHidden(contextMenu);
   contextMenu.hidePopup();
   yield hiddenPromise;
 });
 
 // Right-click on the searchbar and moving it to the menu
 // and back should move the search-container instead.
-add_task(function() {
+add_task(function*() {
   let searchbar = document.getElementById("searchbar");
   gCustomizeMode.addToPanel(searchbar);
   let placement = CustomizableUI.getPlacementOfWidget("search-container");
   is(placement.area, CustomizableUI.AREA_PANEL, "Should be in panel");
 
   let shownPanelPromise = promisePanelShown(window);
   PanelUI.toggle({type: "command"});
   yield shownPanelPromise;
@@ -164,17 +164,17 @@ add_task(function() {
   is(placement, null, "Should be in palette");
   CustomizableUI.reset();
   placement = CustomizableUI.getPlacementOfWidget("search-container");
   is(placement.area, CustomizableUI.AREA_NAVBAR, "Should be in navbar");
 });
 
 // Right-click on an item within the menu panel should
 // show a context menu with options to move it.
-add_task(function() {
+add_task(function*() {
   let shownPanelPromise = promisePanelShown(window);
   PanelUI.toggle({type: "command"});
   yield shownPanelPromise;
 
   let contextMenu = document.getElementById("customizationPanelItemContextMenu");
   let shownContextPromise = popupShown(contextMenu);
   let newWindowButton = document.getElementById("new-window-button");
   ok(newWindowButton, "new-window-button was found");
@@ -197,17 +197,17 @@ add_task(function() {
 
   let hiddenPromise = promisePanelHidden(window);
   PanelUI.toggle({type: "command"});
   yield hiddenPromise;
 });
 
 // Right-click on the home button while in customization mode
 // should show a context menu with options to move it.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let contextMenu = document.getElementById("toolbar-context-menu");
   let shownPromise = popupShown(contextMenu);
   let homeButton = document.getElementById("wrapper-home-button");
   EventUtils.synthesizeMouse(homeButton, 2, 2, {type: "contextmenu", button: 2});
   yield shownPromise;
 
   let expectedEntries = [
@@ -227,17 +227,17 @@ add_task(function() {
 
   let hiddenContextPromise = popupHidden(contextMenu);
   contextMenu.hidePopup();
   yield hiddenContextPromise;
 });
 
 // Right-click on an item in the palette should
 // show a context menu with options to move it.
-add_task(function() {
+add_task(function*() {
   let contextMenu = document.getElementById("customizationPaletteItemContextMenu");
   let shownPromise = popupShown(contextMenu);
   let openFileButton = document.getElementById("wrapper-open-file-button");
   EventUtils.synthesizeMouse(openFileButton, 2, 2, {type: "contextmenu", button: 2});
   yield shownPromise;
 
   let expectedEntries = [
     [".customize-context-addToToolbar", true],
@@ -247,17 +247,17 @@ add_task(function() {
 
   let hiddenContextPromise = popupHidden(contextMenu);
   contextMenu.hidePopup();
   yield hiddenContextPromise;
 });
 
 // Right-click on an item in the panel while in customization mode
 // should show a context menu with options to move it.
-add_task(function() {
+add_task(function*() {
   let contextMenu = document.getElementById("customizationPanelItemContextMenu");
   let shownPromise = popupShown(contextMenu);
   let newWindowButton = document.getElementById("wrapper-new-window-button");
   EventUtils.synthesizeMouse(newWindowButton, 2, 2, {type: "contextmenu", button: 2});
   yield shownPromise;
 
   let expectedEntries = [
     [".customize-context-moveToToolbar", true],
@@ -270,17 +270,17 @@ add_task(function() {
   let hiddenContextPromise = popupHidden(contextMenu);
   contextMenu.hidePopup();
   yield hiddenContextPromise;
   yield endCustomizing();
 });
 
 // Test the toolbarbutton panel context menu in customization mode
 // without opening the panel before customization mode
-add_task(function() {
+add_task(function*() {
   this.otherWin = yield openAndLoadWindow(null, true);
 
   yield new Promise(resolve => waitForFocus(resolve, this.otherWin));
 
   yield startCustomizing(this.otherWin);
 
   let contextMenu = this.otherWin.document.getElementById("customizationPanelItemContextMenu");
   let shownPromise = popupShown(contextMenu);
@@ -303,17 +303,17 @@ add_task(function() {
   yield promiseWindowClosed(this.otherWin);
   this.otherWin = null;
 
   yield new Promise(resolve => waitForFocus(resolve, window));
 });
 
 // Bug 945191 - Combined buttons show wrong context menu options
 // when they are in the toolbar.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let contextMenu = document.getElementById("customizationPanelItemContextMenu");
   let shownPromise = popupShown(contextMenu);
   let zoomControls = document.getElementById("wrapper-zoom-controls");
   EventUtils.synthesizeMouse(zoomControls, 2, 2, {type: "contextmenu", button: 2});
   yield shownPromise;
   // Execute the command to move the item from the panel to the toolbar.
   contextMenu.childNodes[0].doCommand();
@@ -347,17 +347,17 @@ add_task(function() {
 
   hiddenPromise = popupHidden(contextMenu);
   contextMenu.hidePopup();
   yield hiddenPromise;
   yield resetCustomization();
 });
 
 // Bug 947586 - After customization, panel items show wrong context menu options
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   yield endCustomizing();
 
   yield PanelUI.show();
 
   let contextMenu = document.getElementById("customizationPanelItemContextMenu");
   let shownContextPromise = popupShown(contextMenu);
   let newWindowButton = document.getElementById("new-window-button");
@@ -381,17 +381,17 @@ add_task(function() {
 
   let hiddenPromise = promisePanelHidden(window);
   PanelUI.hide();
   yield hiddenPromise;
 });
 
 
 // Bug 982027 - moving icon around removes custom context menu.
-add_task(function() {
+add_task(function*() {
   let widgetId = "custom-context-menu-toolbarbutton";
   let expectedContext = "myfancycontext";
   let widget = createDummyXULButton(widgetId, "Test ctxt menu");
   widget.setAttribute("context", expectedContext);
   CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_NAVBAR);
   is(widget.getAttribute("context"), expectedContext, "Should have context menu when added to the toolbar.");
 
   yield startCustomizing();
--- a/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js
+++ b/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 requestLongerTimeout(5);
 
 // Dragging the zoom controls to be before the print button should not move any controls.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let zoomControls = document.getElementById("zoom-controls");
   let printButton = document.getElementById("print-button");
   let placementsAfterMove = ["edit-controls",
                              "new-window-button",
                              "privatebrowsing-button",
                              "save-page-button",
                              "zoom-controls",
@@ -30,17 +30,17 @@ add_task(function() {
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   let newWindowButton = document.getElementById("new-window-button");
   simulateItemDrag(zoomControls, newWindowButton);
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
 // Dragging the zoom controls to be before the save button should not move any controls.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let zoomControls = document.getElementById("zoom-controls");
   let savePageButton = document.getElementById("save-page-button");
   let placementsAfterMove = ["edit-controls",
                              "zoom-controls",
                              "new-window-button",
                              "privatebrowsing-button",
                              "save-page-button",
@@ -56,17 +56,17 @@ add_task(function() {
   removeDeveloperButtonIfDevEdition(placementsAfterMove);
   simulateItemDrag(zoomControls, savePageButton);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   ok(CustomizableUI.inDefaultState, "Should be in default state.");
 });
 
 
 // Dragging the zoom controls to be before the new-window button should not move any widgets.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let zoomControls = document.getElementById("zoom-controls");
   let newWindowButton = document.getElementById("new-window-button");
   let placementsAfterMove = ["edit-controls",
                              "zoom-controls",
                              "new-window-button",
                              "privatebrowsing-button",
                              "save-page-button",
@@ -81,17 +81,17 @@ add_task(function() {
                             ];
   removeDeveloperButtonIfDevEdition(placementsAfterMove);
   simulateItemDrag(zoomControls, newWindowButton);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
 // Dragging the zoom controls to be before the history-panelmenu should move the zoom-controls in to the row higher than the history-panelmenu.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let zoomControls = document.getElementById("zoom-controls");
   let historyPanelMenu = document.getElementById("history-panelmenu");
   let placementsAfterMove = ["edit-controls",
                              "new-window-button",
                              "privatebrowsing-button",
                              "save-page-button",
                              "zoom-controls",
@@ -110,17 +110,17 @@ add_task(function() {
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   let newWindowButton = document.getElementById("new-window-button");
   simulateItemDrag(zoomControls, newWindowButton);
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
 // Dragging the zoom controls to be before the preferences-button should move the zoom-controls
 // in to the row higher than the preferences-button.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let zoomControls = document.getElementById("zoom-controls");
   let preferencesButton = document.getElementById("preferences-button");
   let placementsAfterMove = ["edit-controls",
                              "new-window-button",
                              "privatebrowsing-button",
                              "save-page-button",
                              "print-button",
@@ -138,17 +138,17 @@ add_task(function() {
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   let newWindowButton = document.getElementById("new-window-button");
   simulateItemDrag(zoomControls, newWindowButton);
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
 // Dragging an item from the palette to before the zoom-controls should move it and two other buttons before the zoom controls.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let openFileButton = document.getElementById("open-file-button");
   let zoomControls = document.getElementById("zoom-controls");
   let placementsAfterInsert = ["edit-controls",
                                "open-file-button",
                                "new-window-button",
                                "privatebrowsing-button",
                                "zoom-controls",
@@ -179,17 +179,17 @@ add_task(function() {
      "The open-file-button should be wrapped by a toolbarpaletteitem");
   let newWindowButton = document.getElementById("new-window-button");
   simulateItemDrag(zoomControls, newWindowButton);
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
 // Dragging an item from the palette to before the edit-controls
 // should move it and two other buttons before the edit and zoom controls.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let openFileButton = document.getElementById("open-file-button");
   let editControls = document.getElementById("edit-controls");
   let placementsAfterInsert = ["open-file-button",
                                "new-window-button",
                                "privatebrowsing-button",
                                "edit-controls",
                                "zoom-controls",
@@ -218,17 +218,17 @@ add_task(function() {
   simulateItemDrag(openFileButton, palette);
   is(openFileButton.parentNode.tagName, "toolbarpaletteitem",
      "The open-file-button should be wrapped by a toolbarpaletteitem");
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
 // Dragging the edit-controls to be before the zoom-controls button
 // should not move any widgets.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let editControls = document.getElementById("edit-controls");
   let zoomControls = document.getElementById("zoom-controls");
   let placementsAfterMove = ["edit-controls",
                              "zoom-controls",
                              "new-window-button",
                              "privatebrowsing-button",
                              "save-page-button",
@@ -244,17 +244,17 @@ add_task(function() {
   removeDeveloperButtonIfDevEdition(placementsAfterMove);
   simulateItemDrag(editControls, zoomControls);
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
 // Dragging the edit-controls to be before the new-window-button should
 // move the zoom-controls before the edit-controls.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let editControls = document.getElementById("edit-controls");
   let newWindowButton = document.getElementById("new-window-button");
   let placementsAfterMove = ["zoom-controls",
                              "edit-controls",
                              "new-window-button",
                              "privatebrowsing-button",
                              "save-page-button",
@@ -273,17 +273,17 @@ add_task(function() {
   let zoomControls = document.getElementById("zoom-controls");
   simulateItemDrag(editControls, zoomControls);
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
 // Dragging the edit-controls to be before the privatebrowsing-button
 // should move the edit-controls in to the row higher than the
 // privatebrowsing-button.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let editControls = document.getElementById("edit-controls");
   let privateBrowsingButton = document.getElementById("privatebrowsing-button");
   let placementsAfterMove = ["zoom-controls",
                              "edit-controls",
                              "new-window-button",
                              "privatebrowsing-button",
                              "save-page-button",
@@ -302,17 +302,17 @@ add_task(function() {
   let zoomControls = document.getElementById("zoom-controls");
   simulateItemDrag(editControls, zoomControls);
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
 // Dragging the edit-controls to be before the save-page-button
 // should move the edit-controls in to the row higher than the
 // save-page-button.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let editControls = document.getElementById("edit-controls");
   let savePageButton = document.getElementById("save-page-button");
   let placementsAfterMove = ["zoom-controls",
                              "edit-controls",
                              "new-window-button",
                              "privatebrowsing-button",
                              "save-page-button",
@@ -330,17 +330,17 @@ add_task(function() {
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   let zoomControls = document.getElementById("zoom-controls");
   simulateItemDrag(editControls, zoomControls);
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
 // Dragging the edit-controls to the panel itself should append
 // the edit controls to the bottom of the panel.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let editControls = document.getElementById("edit-controls");
   let panel = document.getElementById(CustomizableUI.AREA_PANEL);
   let placementsAfterMove = ["zoom-controls",
                              "new-window-button",
                              "privatebrowsing-button",
                              "save-page-button",
                              "print-button",
@@ -358,17 +358,17 @@ add_task(function() {
   assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
   let zoomControls = document.getElementById("zoom-controls");
   simulateItemDrag(editControls, zoomControls);
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
 // Dragging the edit-controls to the customization-palette and
 // back should work.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let editControls = document.getElementById("edit-controls");
   let palette = document.getElementById("customization-palette");
   let placementsAfterMove = ["zoom-controls",
                              "new-window-button",
                              "privatebrowsing-button",
                              "save-page-button",
                              "print-button",
@@ -394,17 +394,17 @@ add_task(function() {
   simulateItemDrag(editControls, zoomControls);
   is(paletteChildElementCount, palette.childElementCount,
      "The palette child count should have returned to its prior value.");
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
 // Dragging the edit-controls to each of the panel placeholders
 // should append the edit-controls to the bottom of the panel.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let editControls = document.getElementById("edit-controls");
   let panel = document.getElementById(CustomizableUI.AREA_PANEL);
   let numPlaceholders = 2;
   for (let i = 0; i < numPlaceholders; i++) {
     // This test relies on there being a specific number of widgets in the
     // panel. The addition of sync-button screwed this up, so we remove it
     // here. We should either fix the tests to not rely on the specific layout,
@@ -432,32 +432,32 @@ add_task(function() {
     let zoomControls = document.getElementById("zoom-controls");
     simulateItemDrag(editControls, zoomControls);
     CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
     ok(CustomizableUI.inDefaultState, "Should still be in default state.");
   }
 });
 
 // Dragging the open-file-button back on to itself should work.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let openFileButton = document.getElementById("open-file-button");
   is(openFileButton.parentNode.tagName, "toolbarpaletteitem",
      "open-file-button should be wrapped by a toolbarpaletteitem");
   simulateItemDrag(openFileButton, openFileButton);
   is(openFileButton.parentNode.tagName, "toolbarpaletteitem",
      "open-file-button should be wrapped by a toolbarpaletteitem");
   let editControls = document.getElementById("edit-controls");
   is(editControls.parentNode.tagName, "toolbarpaletteitem",
      "edit-controls should be wrapped by a toolbarpaletteitem");
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
 // Dragging a small button onto the last big button should work.
-add_task(function() {
+add_task(function*() {
   // Bug 1007910 requires there be a placeholder on the final row for this
   // test to work as written. The addition of sync-button meant that's not true
   // so we remove it from here. Bug 1229236 is for these tests to be smarter.
   CustomizableUI.removeWidgetFromArea("sync-button");
   yield startCustomizing();
   let editControls = document.getElementById("edit-controls");
   let panel = document.getElementById(CustomizableUI.AREA_PANEL);
   let target = panel.getElementsByClassName("panel-customization-placeholder")[0];
@@ -486,12 +486,12 @@ add_task(function() {
   let palette = document.getElementById("customization-palette");
   let zoomControls = document.getElementById("zoom-controls");
   simulateItemDrag(button, palette);
   simulateItemDrag(editControls, zoomControls);
   CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield endCustomizing();
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_884402_customize_from_overflow.js
+++ b/browser/components/customizableui/test/browser_884402_customize_from_overflow.js
@@ -7,17 +7,17 @@ const isOSX = (Services.appinfo.OS === "
 var originalWindowWidth;
 registerCleanupFunction(function() {
   overflowPanel.removeAttribute("animate");
   window.resizeTo(originalWindowWidth, window.outerHeight);
 });
 
 // Right-click on an item within the overflow panel should
 // show a context menu with options to move it.
-add_task(function() {
+add_task(function*() {
 
   overflowPanel.setAttribute("animate", "false");
 
   originalWindowWidth = window.outerWidth;
   let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
   ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
   let oldChildCount = navbar.customizationTarget.childElementCount;
   window.resizeTo(400, window.outerHeight);
--- a/browser/components/customizableui/test/browser_885052_customize_mode_observers_disabed.js
+++ b/browser/components/customizableui/test/browser_885052_customize_mode_observers_disabed.js
@@ -5,17 +5,17 @@
 "use strict";
 
 function isFullscreenSizeMode() {
   let sizemode = document.documentElement.getAttribute("sizemode");
   return sizemode == "fullscreen";
 }
 
 // Observers should be disabled when in customization mode.
-add_task(function() {
+add_task(function*() {
   // Open and close the panel to make sure that the
   // area is generated before getting a child of the area.
   let shownPanelPromise = promisePanelShown(window);
   PanelUI.toggle({type: "command"});
   yield shownPanelPromise;
   let hiddenPanelPromise = promisePanelHidden(window);
   PanelUI.toggle({type: "command"});
   yield hiddenPanelPromise;
--- a/browser/components/customizableui/test/browser_885530_showInPrivateBrowsing.js
+++ b/browser/components/customizableui/test/browser_885530_showInPrivateBrowsing.js
@@ -25,17 +25,17 @@ add_task(function() {
   ok(wrapper.showInPrivateBrowsing,
      "showInPrivateBrowsing should have defaulted to true.");
   CustomizableUI.destroyWidget(kWidgetId);
 });
 
 // Add a widget via the API with showInPrivateBrowsing set to false
 // and ensure it does not appear in pre-existing or newly created
 // private windows.
-add_task(function() {
+add_task(function*() {
   let plain1 = yield openAndLoadWindow();
   let private1 = yield openAndLoadWindow({private: true});
   CustomizableUI.createWidget({
     id: kWidgetId,
     removable: true,
     showInPrivateBrowsing: false
   });
   CustomizableUI.addWidgetToArea(kWidgetId,
@@ -75,17 +75,17 @@ add_task(function() {
   yield Promise.all([plain1, plain2, private1, private2].map(promiseWindowClosed));
 
   CustomizableUI.destroyWidget("some-widget");
 });
 
 // Add a widget via the API with showInPrivateBrowsing set to true,
 // and ensure that it appears in pre-existing or newly created
 // private browsing windows.
-add_task(function() {
+add_task(function*() {
   let plain1 = yield openAndLoadWindow();
   let private1 = yield openAndLoadWindow({private: true});
 
   CustomizableUI.createWidget({
     id: kWidgetId,
     removable: true,
     showInPrivateBrowsing: true
   });
@@ -124,11 +124,11 @@ add_task(function() {
   assertWidgetExists(private1, false);
   assertWidgetExists(private2, false);
 
   yield Promise.all([plain1, plain2, private1, private2].map(promiseWindowClosed));
 
   CustomizableUI.destroyWidget("some-widget");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_886323_buildArea_removable_nodes.js
+++ b/browser/components/customizableui/test/browser_886323_buildArea_removable_nodes.js
@@ -6,17 +6,17 @@
 
 const kButtonId = "test-886323-removable-moved-node";
 const kLazyAreaId = "test-886323-lazy-area-for-removability-testing";
 
 var gNavBar = document.getElementById(CustomizableUI.AREA_NAVBAR);
 var gLazyArea;
 
 // Removable nodes shouldn't be moved by buildArea
-add_task(function() {
+add_task(function*() {
   let dummyBtn = createDummyXULButton(kButtonId, "Dummy");
   dummyBtn.setAttribute("removable", "true");
   gNavBar.customizationTarget.appendChild(dummyBtn);
   let popupSet = document.getElementById("mainPopupSet");
   gLazyArea = document.createElementNS(kNSXUL, "panel");
   gLazyArea.id = kLazyAreaId;
   gLazyArea.setAttribute("hidden", "true");
   popupSet.appendChild(gLazyArea);
@@ -36,11 +36,11 @@ add_task(function() {
      "Button shouldn't actually have moved as it's not removable");
   btn = document.getElementById(kButtonId);
   if (btn) btn.remove();
   CustomizableUI.removeWidgetFromArea(kButtonId);
   CustomizableUI.unregisterArea(kLazyAreaId);
   gLazyArea.remove();
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_887438_currentset_shim.js
+++ b/browser/components/customizableui/test/browser_887438_currentset_shim.js
@@ -65,11 +65,11 @@ add_task(function() {
     let feedParent = feedBtn.parentNode;
     ok(feedParent == navbarCT || feedParent == overflowPanelList,
        "Feed button should be in navbar or overflow");
   }
   navbar.currentSet = currentSet;
   is(currentSet, navbar.currentSet, "Should be able to return to original state.");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_888817_currentset_updating.js
+++ b/browser/components/customizableui/test/browser_888817_currentset_updating.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Adding, moving and removing items should update the relevant currentset attributes
-add_task(function() {
+add_task(function*() {
   ok(CustomizableUI.inDefaultState, "Should be in the default state when we start");
   let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
   setToolbarVisibility(personalbar, true);
   ok(!CustomizableUI.inDefaultState, "Making the bookmarks toolbar visible takes it out of the default state");
 
   let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
   personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
   let navbarCurrentset = navbar.getAttribute("currentset") || navbar.currentSet;
@@ -45,13 +45,13 @@ add_task(function() {
      "Should have updated currentSet after remove.");
   is(otherPersonalbar.getAttribute("currentset"), personalbarCurrentset,
      "Should have updated other window's currentSet after remove.");
 
   yield promiseWindowClosed(otherWin);
   // Reset in asyncCleanup will put our button back for us.
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
   setToolbarVisibility(personalbar, false);
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_889120_customize_tab_merging.js
+++ b/browser/components/customizableui/test/browser_889120_customize_tab_merging.js
@@ -3,23 +3,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const kTestToolbarId = "test-empty-drag";
 
 // Attempting to switch quickly from one tab to another to see whether the state changes
 // correctly.
-add_task(function CheckBasicCustomizeMode() {
+add_task(function* CheckBasicCustomizeMode() {
   yield startCustomizing();
   ok(CustomizationHandler.isCustomizing(), "We should be in customize mode");
   yield endCustomizing();
   ok(!CustomizationHandler.isCustomizing(), "We should not be in customize mode");
 });
-add_task(function CheckQuickCustomizeModeSwitch() {
+add_task(function* CheckQuickCustomizeModeSwitch() {
   let tab1 = gBrowser.addTab("about:newtab");
   gBrowser.selectedTab = tab1;
   let tab2 = gBrowser.addTab("about:customizing");
   let tab3 = gBrowser.addTab("about:newtab");
   gBrowser.selectedTab = tab2;
   try {
     yield waitForCondition(() => CustomizationHandler.isEnteringCustomizeMode);
   } catch (ex) {
@@ -33,12 +33,12 @@ add_task(function CheckQuickCustomizeMod
     Cu.reportError(ex);
   }
   ok(!CustomizationHandler.isCustomizing(), "Should not be entering customize mode");
   gBrowser.removeTab(tab1);
   gBrowser.removeTab(tab2);
   gBrowser.removeTab(tab3);
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield endCustomizing();
 });
 
--- a/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js
+++ b/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 requestLongerTimeout(2);
 
 // One orphaned item should have two placeholders next to it.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
 
   if (isInDevEdition()) {
     CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_PANEL);
     ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
   }
   if (!isInDevEdition()) {
     ok(CustomizableUI.inDefaultState, "Should be in default state.");
@@ -37,17 +37,17 @@ add_task(function() {
     CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_NAVBAR, 2);
   }
 
   CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
 // Two orphaned items should have one placeholder next to them (case 1).
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
 
   if (isInDevEdition()) {
     CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_PANEL);
   }
 
   // This test relies on an exact number of widgets being in the panel.
   // Remove the sync-button to satisfy that. (bug 1229236)
@@ -81,17 +81,17 @@ add_task(function() {
     CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_NAVBAR, 2);
   }
 
   CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
 // Two orphaned items should have one placeholder next to them (case 2).
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
 
   if (isInDevEdition()) {
     CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_PANEL);
   }
   // This test relies on an exact number of widgets being in the panel.
   // Remove the sync-button to satisfy that. (bug 1229236)
   CustomizableUI.removeWidgetFromArea("sync-button");
@@ -123,17 +123,17 @@ add_task(function() {
     CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_NAVBAR, 2);
   }
 
   CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
 // A wide widget at the bottom of the panel should have three placeholders after it.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
 
   if (isInDevEdition()) {
     CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_PANEL);
   }
 
   // This test relies on an exact number of widgets being in the panel.
   // Remove the sync-button to satisfy that. (bug 1229236)
@@ -167,17 +167,17 @@ add_task(function() {
     CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_NAVBAR, 2);
   }
 
   CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
   ok(CustomizableUI.inDefaultState, "Should be in default state again.");
 });
 
 // The default placements should have two placeholders at the bottom (or 1 in win8).
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let numPlaceholders = -1;
 
   if (isInDevEdition()) {
     numPlaceholders = 3;
   } else {
     numPlaceholders = 2;
   }
@@ -194,17 +194,17 @@ add_task(function() {
   yield endCustomizing();
   yield startCustomizing();
   is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders after re-entering");
 
   CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
   ok(CustomizableUI.inDefaultState, "Should still be in default state.");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield endCustomizing();
   yield resetCustomization();
 });
 
 function getVisiblePlaceholderCount(aPanel) {
   let visiblePlaceholders = aPanel.querySelectorAll(".panel-customization-placeholder:not([hidden=true])");
   return visiblePlaceholders.length;
 }
--- a/browser/components/customizableui/test/browser_890262_destroyWidget_after_add_to_panel.js
+++ b/browser/components/customizableui/test/browser_890262_destroyWidget_after_add_to_panel.js
@@ -41,17 +41,17 @@ add_task(function() {
     CustomizableUI.destroyWidget(kWidget2Id);
   } catch (ex) {
     Cu.reportError(ex);
     noError = false;
   }
   ok(noError, "Shouldn't throw an exception for a widget that was added to a not-yet-constructed area");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   let lazyArea = document.getElementById(kLazyAreaId);
   if (lazyArea) {
     lazyArea.remove();
   }
   try {
     CustomizableUI.unregisterArea(kLazyAreaId);
   } catch (ex) {} // If we didn't register successfully for some reason
   yield resetCustomization();
--- a/browser/components/customizableui/test/browser_892955_isWidgetRemovable_for_removed_widgets.js
+++ b/browser/components/customizableui/test/browser_892955_isWidgetRemovable_for_removed_widgets.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const kWidgetId = "test-892955-remove-widget";
 
 // Removing a destroyed widget should work.
-add_task(function() {
+add_task(function*() {
   let widgetSpec = {
     id: kWidgetId,
     defaultArea: CustomizableUI.AREA_NAVBAR
   };
 
   CustomizableUI.createWidget(widgetSpec);
   CustomizableUI.destroyWidget(kWidgetId);
   let noError = true;
@@ -20,11 +20,11 @@ add_task(function() {
     CustomizableUI.removeWidgetFromArea(kWidgetId);
   } catch (ex) {
     noError = false;
     Cu.reportError(ex);
   }
   ok(noError, "Shouldn't throw an error removing a destroyed widget.");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_892956_destroyWidget_defaultPlacements.js
+++ b/browser/components/customizableui/test/browser_892956_destroyWidget_defaultPlacements.js
@@ -2,23 +2,23 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const kWidgetId = "test-892956-destroyWidget-defaultPlacement";
 
 // destroyWidget should clean up defaultPlacements if the widget had a defaultArea
-add_task(function() {
+add_task(function*() {
   ok(CustomizableUI.inDefaultState, "Should be in the default state when we start");
 
   let widgetSpec = {
     id: kWidgetId,
     defaultArea: CustomizableUI.AREA_NAVBAR
   };
   CustomizableUI.createWidget(widgetSpec);
   CustomizableUI.destroyWidget(kWidgetId);
   ok(CustomizableUI.inDefaultState, "Should be in the default state when we finish");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_901207_searchbar_in_panel.js
+++ b/browser/components/customizableui/test/browser_901207_searchbar_in_panel.js
@@ -22,17 +22,17 @@ function* waitForSearchBarFocus()
   let searchbar = document.getElementById("searchbar");
   yield waitForCondition(function () {
     logActiveElement();
     return document.activeElement === searchbar.textbox.inputField;
   });
 }
 
 // Ctrl+K should open the menu panel and focus the search bar if the search bar is in the panel.
-add_task(function() {
+add_task(function*() {
   let searchbar = document.getElementById("searchbar");
   gCustomizeMode.addToPanel(searchbar);
   let placement = CustomizableUI.getPlacementOfWidget("search-container");
   is(placement.area, CustomizableUI.AREA_PANEL, "Should be in panel");
 
   let shownPanelPromise = promisePanelShown(window);
   sendWebSearchKeyCommand();
   yield shownPanelPromise;
@@ -41,17 +41,17 @@ add_task(function() {
 
   let hiddenPanelPromise = promisePanelHidden(window);
   EventUtils.synthesizeKey("VK_ESCAPE", {});
   yield hiddenPanelPromise;
   CustomizableUI.reset();
 });
 
 // Ctrl+K should give focus to the searchbar when the searchbar is in the menupanel and the panel is already opened.
-add_task(function() {
+add_task(function*() {
   let searchbar = document.getElementById("searchbar");
   gCustomizeMode.addToPanel(searchbar);
   let placement = CustomizableUI.getPlacementOfWidget("search-container");
   is(placement.area, CustomizableUI.AREA_PANEL, "Should be in panel");
 
   let shownPanelPromise = promisePanelShown(window);
   PanelUI.toggle({type: "command"});
   yield shownPanelPromise;
@@ -62,17 +62,17 @@ add_task(function() {
 
   let hiddenPanelPromise = promisePanelHidden(window);
   EventUtils.synthesizeKey("VK_ESCAPE", {});
   yield hiddenPanelPromise;
   CustomizableUI.reset();
 });
 
 // Ctrl+K should open the overflow panel and focus the search bar if the search bar is overflowed.
-add_task(function() {
+add_task(function*() {
   this.originalWindowWidth = window.outerWidth;
   let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
   ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
   ok(CustomizableUI.inDefaultState, "Should start in default state.");
 
   window.resizeTo(360, window.outerHeight);
   yield waitForCondition(() => navbar.getAttribute("overflowing") == "true");
   ok(!navbar.querySelector("#search-container"), "Search container should be overflowing");
@@ -91,27 +91,27 @@ add_task(function() {
   yield hiddenPanelPromise;
   navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
   window.resizeTo(this.originalWindowWidth, window.outerHeight);
   yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
   ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar.");
 });
 
 // Ctrl+K should focus the search bar if it is in the navbar and not overflowing.
-add_task(function() {
+add_task(function*() {
   let placement = CustomizableUI.getPlacementOfWidget("search-container");
   is(placement.area, CustomizableUI.AREA_NAVBAR, "Should be in nav-bar");
 
   sendWebSearchKeyCommand();
 
   yield waitForSearchBarFocus();
 });
 
 // Ctrl+K should open the search page if the search bar has been customized out.
-add_task(function() {
+add_task(function*() {
   try {
     expectOpenUILinkInCall = true;
     CustomizableUI.removeWidgetFromArea("search-container");
     let placement = CustomizableUI.getPlacementOfWidget("search-container");
     is(placement, null, "Search container should be in palette");
 
     openUILinkInCalled = false;
 
--- a/browser/components/customizableui/test/browser_909779_overflow_toolbars_new_window.js
+++ b/browser/components/customizableui/test/browser_909779_overflow_toolbars_new_window.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Resize to a small window, open a new window, check that new window handles overflow properly
-add_task(function() {
+add_task(function*() {
   let originalWindowWidth = window.outerWidth;
   let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
   ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
   let oldChildCount = navbar.customizationTarget.childElementCount;
   window.resizeTo(400, window.outerHeight);
   yield waitForCondition(() => navbar.hasAttribute("overflowing"));
   ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
 
@@ -21,11 +21,11 @@ add_task(function() {
   ok(otherNavBar.hasAttribute("overflowing"), "Other window should have an overflowing toolbar.");
   yield promiseWindowClosed(newWindow);
 
   window.resizeTo(originalWindowWidth, window.outerHeight);
   yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
   ok(!navbar.hasAttribute("overflowing"), "Should no longer have an overflowing toolbar.");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_913972_currentset_overflow.js
+++ b/browser/components/customizableui/test/browser_913972_currentset_overflow.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
 
 // Resize to a small window, resize back, shouldn't affect currentSet
-add_task(function() {
+add_task(function*() {
   let originalWindowWidth = window.outerWidth;
   let oldCurrentSet = navbar.currentSet;
   ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
   ok(CustomizableUI.inDefaultState, "Should start in default state.");
   let oldChildCount = navbar.customizationTarget.childElementCount;
   window.resizeTo(400, window.outerHeight);
   yield waitForCondition(() => navbar.hasAttribute("overflowing"));
   ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
@@ -34,22 +34,22 @@ add_task(function() {
     }
     is(placements[placementCounter++], node.id, "Nodes should match after overflow");
   }
   is(placements.length, placementCounter, "Should have as many nodes as expected");
   is(navbar.customizationTarget.childElementCount, oldChildCount, "Number of nodes should match");
 });
 
 // Enter and exit customization mode, check that currentSet works
-add_task(function() {
+add_task(function*() {
   let oldCurrentSet = navbar.currentSet;
   ok(CustomizableUI.inDefaultState, "Should start in default state.");
   yield startCustomizing();
   ok(CustomizableUI.inDefaultState, "Should be in default state in customization mode.");
   is(navbar.currentSet, oldCurrentSet, "Currentset should be the same in customization mode.");
   yield endCustomizing();
   ok(CustomizableUI.inDefaultState, "Should be in default state after customization mode.");
   is(navbar.currentSet, oldCurrentSet, "Currentset should be the same after customization mode.");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_914138_widget_API_overflowable_toolbar.js
+++ b/browser/components/customizableui/test/browser_914138_widget_API_overflowable_toolbar.js
@@ -13,17 +13,17 @@ const kTestBtn3 = "test-createWidget-ove
 const kHomeBtn = "home-button";
 const kDownloadsBtn = "downloads-button";
 const kSearchBox = "search-container";
 const kStarBtn = "bookmarks-menu-button";
 
 var originalWindowWidth;
 
 // Adding a widget should add it next to the widget it's being inserted next to.
-add_task(function() {
+add_task(function*() {
   originalWindowWidth = window.outerWidth;
   createDummyXULButton(kTestBtn1, "Test");
   ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
   ok(CustomizableUI.inDefaultState, "Should start in default state.");
 
   window.resizeTo(400, window.outerHeight);
   yield waitForCondition(() => navbar.hasAttribute("overflowing"));
   ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
@@ -54,17 +54,17 @@ add_task(function() {
   if (el) {
     CustomizableUI.removeWidgetFromArea(kTestBtn1);
     el.remove();
   }
   window.resizeTo(originalWindowWidth, window.outerHeight);
 });
 
 // Removing a widget should remove it from the overflow list if that is where it is, and update it accordingly.
-add_task(function() {
+add_task(function*() {
   createDummyXULButton(kTestBtn2, "Test");
   ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
   ok(CustomizableUI.inDefaultState, "Should start in default state.");
   CustomizableUI.addWidgetToArea(kTestBtn2, navbar.id);
   ok(!navbar.hasAttribute("overflowing"), "Should still have a non-overflowing toolbar.");
 
   window.resizeTo(400, window.outerHeight);
   yield waitForCondition(() => navbar.hasAttribute("overflowing"));
@@ -85,17 +85,17 @@ add_task(function() {
   if (el) {
     CustomizableUI.removeWidgetFromArea(kTestBtn2);
     el.remove();
   }
   window.resizeTo(originalWindowWidth, window.outerHeight);
 });
 
 // Constructing a widget while overflown should set the right class on it.
-add_task(function() {
+add_task(function*() {
   originalWindowWidth = window.outerWidth;
   ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
   ok(CustomizableUI.inDefaultState, "Should start in default state.");
 
   window.resizeTo(400, window.outerHeight);
   yield waitForCondition(() => navbar.hasAttribute("overflowing"));
   ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
   ok(!navbar.querySelector("#" + kHomeBtn), "Home button should no longer be in the navbar");
@@ -120,12 +120,12 @@ add_task(function() {
 
   CustomizableUI.removeWidgetFromArea(kTestBtn3);
   testNode = document.getElementById(kTestBtn3);
   ok(!testNode, "Test button should be gone");
   CustomizableUI.destroyWidget(kTestBtn3);
   window.resizeTo(originalWindowWidth, window.outerHeight);
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   window.resizeTo(originalWindowWidth, window.outerHeight);
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_914863_disabled_help_quit_buttons.js
+++ b/browser/components/customizableui/test/browser_914863_disabled_help_quit_buttons.js
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Entering then exiting customization mode should reenable the Help and Exit buttons.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let helpButton = document.getElementById("PanelUI-help");
   let quitButton = document.getElementById("PanelUI-quit");
   ok(helpButton.getAttribute("disabled") == "true", "Help button should be disabled while in customization mode.");
   ok(quitButton.getAttribute("disabled") == "true", "Quit button should be disabled while in customization mode.");
   yield endCustomizing();
 
   ok(!helpButton.hasAttribute("disabled"), "Help button should not be disabled.");
--- a/browser/components/customizableui/test/browser_918049_skipintoolbarset_dnd.js
+++ b/browser/components/customizableui/test/browser_918049_skipintoolbarset_dnd.js
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var navbar;
 var skippedItem;
 
 // Attempting to drag a skipintoolbarset item should work.
-add_task(function() {
+add_task(function*() {
   navbar = document.getElementById("nav-bar");
   skippedItem = document.createElement("toolbarbutton");
   skippedItem.id = "test-skipintoolbarset-item";
   skippedItem.setAttribute("label", "Test");
   skippedItem.setAttribute("skipintoolbarset", "true");
   skippedItem.setAttribute("removable", "true");
   navbar.customizationTarget.appendChild(skippedItem);
   let downloadsButton = document.getElementById("downloads-button");
@@ -26,13 +26,13 @@ add_task(function() {
      downloadsButton.parentNode.id, "Should be next to downloads button");
   simulateItemDrag(downloadsButton, skippedItem);
   let downloadWrapper = downloadsButton.parentNode;
   is(downloadWrapper.nextSibling && downloadWrapper.nextSibling.id,
      skippedItem.parentNode.id, "Should be next to skipintoolbarset item");
   ok(CustomizableUI.inDefaultState, "Should still be in default state");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield endCustomizing();
   skippedItem.remove();
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_923857_customize_mode_event_wrapping_during_reset.js
+++ b/browser/components/customizableui/test/browser_923857_customize_mode_event_wrapping_during_reset.js
@@ -1,25 +1,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Customize mode reset button should revert correctly
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let devButton = document.getElementById("developer-button");
   let downloadsButton = document.getElementById("downloads-button");
   let searchBox = document.getElementById("search-container");
   let palette = document.getElementById("customization-palette");
   ok(devButton && downloadsButton && searchBox && palette, "Stuff should exist");
   simulateItemDrag(devButton, downloadsButton);
   simulateItemDrag(searchBox, palette);
   gCustomizeMode.reset();
   yield waitForCondition(() => !gCustomizeMode.resetting);
   ok(CustomizableUI.inDefaultState, "Should be back in default state");
   yield endCustomizing();
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_927717_customize_drag_empty_toolbar.js
+++ b/browser/components/customizableui/test/browser_927717_customize_drag_empty_toolbar.js
@@ -2,25 +2,25 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const kTestToolbarId = "test-empty-drag";
 
 // Attempting to drag an item to an empty container should work.
-add_task(function() {
+add_task(function*() {
   yield createToolbarWithPlacements(kTestToolbarId, []);
   yield startCustomizing();
   let downloadButton = document.getElementById("downloads-button");
   let customToolbar = document.getElementById(kTestToolbarId);
   simulateItemDrag(downloadButton, customToolbar);
   assertAreaPlacements(kTestToolbarId, ["downloads-button"]);
   ok(downloadButton.parentNode && downloadButton.parentNode.parentNode == customToolbar,
      "Button should really be in toolbar");
   yield endCustomizing();
   removeCustomToolbars();
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield endCustomizing();
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_932928_show_notice_when_palette_empty.js
+++ b/browser/components/customizableui/test/browser_932928_show_notice_when_palette_empty.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // There should be an advert to get more addons when the palette is empty.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let visiblePalette = document.getElementById("customization-palette");
   let emptyPaletteNotice = document.getElementById("customization-empty");
   is(emptyPaletteNotice.hidden, true, "The empty palette notice should not be shown when there are items in the palette.");
 
   while (visiblePalette.childElementCount) {
     gCustomizeMode.addToToolbar(visiblePalette.children[0]);
   }
@@ -24,12 +24,12 @@ add_task(function() {
   is(emptyPaletteNotice.hidden, false,
      "The empty palette notice should be shown when there are no items in the palette and cust. mode is re-entered.");
 
   gCustomizeMode.removeFromArea(document.getElementById("wrapper-home-button"));
   is(emptyPaletteNotice.hidden, true,
      "The empty palette notice should not be shown when there is at least one item in the palette.");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield endCustomizing();
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_934113_menubar_removable.js
+++ b/browser/components/customizableui/test/browser_934113_menubar_removable.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Attempting to drag the menubar to the navbar shouldn't work.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   let menuItems = document.getElementById("menubar-items");
   let navbar = document.getElementById("nav-bar");
   let menubar = document.getElementById("toolbar-menubar");
   // Force the menu to be shown.
   const kAutohide = menubar.getAttribute("autohide");
   menubar.setAttribute("autohide", "false");
   simulateItemDrag(menuItems, navbar.customizationTarget);
@@ -19,12 +19,12 @@ add_task(function() {
   ok(!navbar.querySelector("#menubar-items"), "Shouldn't find menubar items in the navbar.");
   ok(menubar.querySelector("#menubar-items"), "Should find menubar items in the menubar.");
   isnot(getAreaWidgetIds("toolbar-menubar").indexOf("menubar-items"), -1,
         "Menubar items shouldn't be missing from the navbar.");
   menubar.setAttribute("autohide", kAutohide);
   yield endCustomizing();
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield endCustomizing();
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_934951_zoom_in_toolbar.js
+++ b/browser/components/customizableui/test/browser_934951_zoom_in_toolbar.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const kTimeoutInMS = 20000;
 
 // Bug 934951 - Zoom controls percentage label doesn't update when it's in the toolbar and you navigate.
-add_task(function() {
+add_task(function*() {
   CustomizableUI.addWidgetToArea("zoom-controls", CustomizableUI.AREA_NAVBAR);
   let tab1 = gBrowser.addTab("about:mozilla");
   yield BrowserTestUtils.browserLoaded(tab1.linkedBrowser);
   let tab2 = gBrowser.addTab("about:robots");
   yield BrowserTestUtils.browserLoaded(tab2.linkedBrowser);
   gBrowser.selectedTab = tab1;
   let zoomResetButton = document.getElementById("zoom-reset-button");
 
--- a/browser/components/customizableui/test/browser_938980_navbar_collapsed.js
+++ b/browser/components/customizableui/test/browser_938980_navbar_collapsed.js
@@ -6,28 +6,28 @@
 
 requestLongerTimeout(2);
 
 var bookmarksToolbar = document.getElementById("PersonalToolbar");
 var navbar = document.getElementById("nav-bar");
 var tabsToolbar = document.getElementById("TabsToolbar");
 
 // Customization reset should restore visibility to default-visible toolbars.
-add_task(function() {
+add_task(function*() {
   is(navbar.collapsed, false, "Test should start with navbar visible");
   setToolbarVisibility(navbar, false);
   is(navbar.collapsed, true, "navbar should be hidden now");
 
   yield resetCustomization();
 
   is(navbar.collapsed, false, "Customization reset should restore visibility to the navbar");
 });
 
 // Customization reset should restore collapsed-state to default-collapsed toolbars.
-add_task(function() {
+add_task(function*() {
   ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
 
   is(bookmarksToolbar.collapsed, true, "Test should start with bookmarks toolbar collapsed");
   ok(bookmarksToolbar.collapsed, "bookmarksToolbar should be collapsed");
   ok(!tabsToolbar.collapsed, "TabsToolbar should not be collapsed");
   is(navbar.collapsed, false, "The nav-bar should be shown by default");
 
   setToolbarVisibility(bookmarksToolbar, true);
@@ -43,17 +43,17 @@ add_task(function() {
 
   is(bookmarksToolbar.collapsed, true, "Customization reset should restore collapsed-state to the bookmarks toolbar");
   ok(!tabsToolbar.collapsed, "TabsToolbar should not be collapsed");
   ok(bookmarksToolbar.collapsed, "The bookmarksToolbar should be collapsed after reset");
   ok(CustomizableUI.inDefaultState, "Everything should be back to default state");
 });
 
 // Check that the menubar will be collapsed by resetting, if the platform supports it.
-add_task(function() {
+add_task(function*() {
   let menubar = document.getElementById("toolbar-menubar");
   const canMenubarCollapse = CustomizableUI.isToolbarDefaultCollapsed(menubar.id);
   if (!canMenubarCollapse) {
     return;
   }
   ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
 
   is(menubar.getBoundingClientRect().height, 0, "menubar should be hidden by default");
@@ -69,17 +69,17 @@ add_task(function() {
 
   yield endCustomizing();
 
   is(menubar.getAttribute("autohide"), "true", "The menubar should have autohide=true after reset");
   is(menubar.getBoundingClientRect().height, 0, "The menubar should have height=0 after reset");
 });
 
 // Customization reset should restore collapsed-state to default-collapsed toolbars.
-add_task(function() {
+add_task(function*() {
   ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
   ok(bookmarksToolbar.collapsed, "bookmarksToolbar should be collapsed");
   ok(!tabsToolbar.collapsed, "TabsToolbar should not be collapsed");
 
   setToolbarVisibility(bookmarksToolbar, true);
   ok(!bookmarksToolbar.collapsed, "bookmarksToolbar should be visible now");
   is(CustomizableUI.inDefaultState, false, "Should no longer be in default state");
 
@@ -95,17 +95,17 @@ add_task(function() {
   ok(bookmarksToolbar.collapsed, "The bookmarksToolbar should be collapsed after reset");
   ok(!tabsToolbar.collapsed, "TabsToolbar should not be collapsed");
   ok(!navbar.collapsed, "The navbar should still be visible after reset");
   ok(CustomizableUI.inDefaultState, "Everything should be back to default state");
   yield endCustomizing();
 });
 
 // Check that the menubar will be collapsed by resetting, if the platform supports it.
-add_task(function() {
+add_task(function*() {
   let menubar = document.getElementById("toolbar-menubar");
   const canMenubarCollapse = CustomizableUI.isToolbarDefaultCollapsed(menubar.id);
   if (!canMenubarCollapse) {
     return;
   }
   ok(CustomizableUI.inDefaultState, "Everything should be in its default state");
   yield startCustomizing();
   let resetButton = document.getElementById("customization-reset-button");
--- a/browser/components/customizableui/test/browser_940013_registerToolbarNode_calls_registerArea.js
+++ b/browser/components/customizableui/test/browser_940013_registerToolbarNode_calls_registerArea.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 const kToolbarId = "test-registerToolbarNode-toolbar";
 const kButtonId = "test-registerToolbarNode-button";
 registerCleanupFunction(cleanup);
 
 // Registering a toolbar with defaultset attribute should work
-add_task(function() {
+add_task(function*() {
   ok(CustomizableUI.inDefaultState, "Everything should be in its default state.");
   let btn = createDummyXULButton(kButtonId);
   let toolbar = document.createElement("toolbar");
   toolbar.id = kToolbarId;
   toolbar.setAttribute("customizable", true);
   toolbar.setAttribute("defaultset", kButtonId);
   gNavToolbox.appendChild(toolbar);
   ok(CustomizableUI.areas.indexOf(kToolbarId) != -1,
@@ -26,17 +26,17 @@ add_task(function() {
   CustomizableUI.unregisterArea(kToolbarId, true);
   toolbar.remove();
   ok(CustomizableUI.inDefaultState, "Everything should be in its default state.");
   btn.remove();
 });
 
 // Registering a toolbar without a defaultset attribute should
 // wait for the registerArea call
-add_task(function() {
+add_task(function*() {
   ok(CustomizableUI.inDefaultState, "Everything should be in its default state.");
   let btn = createDummyXULButton(kButtonId);
   let toolbar = document.createElement("toolbar");
   toolbar.id = kToolbarId;
   toolbar.setAttribute("customizable", true);
   gNavToolbox.appendChild(toolbar);
   ok(CustomizableUI.areas.indexOf(kToolbarId) == -1,
      "Toolbar should not yet have been registered automatically.");
@@ -48,17 +48,17 @@ add_task(function() {
   assertAreaPlacements(kToolbarId, [kButtonId]);
   ok(!CustomizableUI.inDefaultState, "No longer in default state after toolbar is registered and visible.");
   CustomizableUI.unregisterArea(kToolbarId, true);
   toolbar.remove();
   ok(CustomizableUI.inDefaultState, "Everything should be in its default state.");
   btn.remove();
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
 
 function cleanup() {
   let toolbar = document.getElementById(kToolbarId);
   if (toolbar) {
     toolbar.remove();
   }
--- a/browser/components/customizableui/test/browser_940307_panel_click_closure_handling.js
+++ b/browser/components/customizableui/test/browser_940307_panel_click_closure_handling.js
@@ -1,30 +1,30 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var button, menuButton;
 /* Clicking a button should close the panel */
-add_task(function() {
+add_task(function*() {
   button = document.createElement("toolbarbutton");
   button.id = "browser_940307_button";
   button.setAttribute("label", "Button");
   PanelUI.contents.appendChild(button);
   yield PanelUI.show();
   let hiddenAgain = promisePanelHidden(window);
   EventUtils.synthesizeMouseAtCenter(button, {});
   yield hiddenAgain;
   button.remove();
 });
 
 /* Clicking a menu button should close the panel, opening the popup shouldn't.  */
-add_task(function() {
+add_task(function*() {
   menuButton = document.createElement("toolbarbutton");
   menuButton.setAttribute("type", "menu-button");
   menuButton.id = "browser_940307_menubutton";
   menuButton.setAttribute("label", "Menu button");
 
   let menuPopup = document.createElement("menupopup");
   menuPopup.id = "browser_940307_menupopup";
 
--- a/browser/components/customizableui/test/browser_940946_removable_from_navbar_customizemode.js
+++ b/browser/components/customizableui/test/browser_940946_removable_from_navbar_customizemode.js
@@ -2,21 +2,21 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const kTestBtnId = "test-removable-navbar-customize-mode";
 
 // Items without the removable attribute in the navbar should be considered non-removable
-add_task(function() {
+add_task(function*() {
   let btn = createDummyXULButton(kTestBtnId, "Test removable in navbar in customize mode");
   document.getElementById("nav-bar").customizationTarget.appendChild(btn);
   yield startCustomizing();
   ok(!CustomizableUI.isWidgetRemovable(kTestBtnId), "Widget should not be considered removable");
   yield endCustomizing();
   document.getElementById(kTestBtnId).remove();
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield endCustomizing();
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_942581_unregisterArea_keeps_placements.js
+++ b/browser/components/customizableui/test/browser_942581_unregisterArea_keeps_placements.js
@@ -5,17 +5,17 @@
 "use strict";
 
 const kToolbarName = "test-unregisterArea-placements-toolbar";
 const kTestWidgetPfx = "test-widget-for-unregisterArea-placements-";
 const kTestWidgetCount = 3;
 registerCleanupFunction(removeCustomToolbars);
 
 // unregisterArea should keep placements by default and restore them when re-adding the area
-add_task(function() {
+add_task(function*() {
   let widgetIds = [];
   for (let i = 0; i < kTestWidgetCount; i++) {
     let id = kTestWidgetPfx + i;
     widgetIds.push(id);
     let spec = {id: id, type: 'button', removable: true, label: "unregisterArea test", tooltiptext: "" + i};
     CustomizableUI.createWidget(spec);
   }
   for (let i = kTestWidgetCount; i < kTestWidgetCount * 2; i++) {
@@ -96,11 +96,11 @@ function checkWidgetFates(aWidgetIds) {
     ok(!document.getElementById(widget), "Widget should not be in the DOM");
     let widgetInPalette = !!gNavToolbox.palette.querySelector("#" + widget);
     let widgetProvider = CustomizableUI.getWidget(widget).provider;
     let widgetIsXULWidget = widgetProvider == CustomizableUI.PROVIDER_XUL;
     is(widgetInPalette, widgetIsXULWidget, "Just XUL Widgets should be in the palette");
   }
 }
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_943683_migration_test.js
+++ b/browser/components/customizableui/test/browser_943683_migration_test.js
@@ -9,17 +9,17 @@ const kWidgetId2 = "test-addonbar-migrat
 
 var addonbar = document.getElementById(CustomizableUI.AREA_ADDONBAR);
 var navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
 
 var btn;
 var btn2;
 
 // Check we migrate normal stuff to the navbar
-add_task(function() {
+add_task(function*() {
   btn = createDummyXULButton(kWidgetId, "Test");
   btn2 = createDummyXULButton(kWidgetId2, "Test2");
   addonbar.insertItem(btn.id);
   ok(btn.parentNode == navbar.customizationTarget, "Button should end up in navbar");
   let migrationArray = addonbar.getMigratedItems();
   is(migrationArray.length, 1, "Should have migrated 1 item");
   is(migrationArray[0], kWidgetId, "Should have migrated our 1 item");
 
--- a/browser/components/customizableui/test/browser_944887_destroyWidget_should_destroy_in_palette.js
+++ b/browser/components/customizableui/test/browser_944887_destroyWidget_should_destroy_in_palette.js
@@ -2,16 +2,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const kWidgetId = "test-destroy-in-palette";
 
 // Check destroyWidget destroys the node if it's in the palette
-add_task(function() {
+add_task(function*() {
   CustomizableUI.createWidget({id: kWidgetId, label: "Test destroying widgets in palette."});
   yield startCustomizing();
   yield endCustomizing();
   ok(gNavToolbox.palette.querySelector("#" + kWidgetId), "Widget still exists in palette.");
   CustomizableUI.destroyWidget(kWidgetId);
   ok(!gNavToolbox.palette.querySelector("#" + kWidgetId), "Widget no longer exists in palette.");
 });
--- a/browser/components/customizableui/test/browser_945739_showInPrivateBrowsing_customize_mode.js
+++ b/browser/components/customizableui/test/browser_945739_showInPrivateBrowsing_customize_mode.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 const kWidgetId = "test-private-browsing-customize-mode-widget";
 
 // Add a widget via the API with showInPrivateBrowsing set to false
 // and ensure it does not appear in the list of unused widgets in private
 // windows.
-add_task(function testPrivateBrowsingCustomizeModeWidget() {
+add_task(function* testPrivateBrowsingCustomizeModeWidget() {
   CustomizableUI.createWidget({
     id: kWidgetId,
     showInPrivateBrowsing: false
   });
 
   let normalWidgetArray = CustomizableUI.getUnusedWidgets(gNavToolbox.palette);
   normalWidgetArray = normalWidgetArray.map((w) => w.id);
   ok(normalWidgetArray.indexOf(kWidgetId) > -1,
@@ -25,11 +25,11 @@ add_task(function testPrivateBrowsingCus
   privateWidgetArray = privateWidgetArray.map((w) => w.id);
   is(privateWidgetArray.indexOf(kWidgetId), -1,
      "Widget should not appear as unused in private window");
   yield promiseWindowClosed(privateWindow);
 
   CustomizableUI.destroyWidget(kWidgetId); 
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_946320_tabs_from_other_computers.js
+++ b/browser/components/customizableui/test/browser_946320_tabs_from_other_computers.js
@@ -6,17 +6,17 @@
 
 var Preferences = Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;
 
 const {FxAccounts, AccountState} = Cu.import("resource://gre/modules/FxAccounts.jsm", {});
 
 // FxA logs can be gotten at via this pref which helps debugging.
 Preferences.set("services.sync.log.appender.dump", "Debug");
 
-add_task(function() {
+add_task(function*() {
   yield PanelUI.show({type: "command"});
 
   let historyButton = document.getElementById("history-panelmenu");
   let historySubview = document.getElementById("PanelUI-history");
   let subviewShownPromise = subviewShown(historySubview);
   historyButton.click();
   yield subviewShownPromise;
 
--- a/browser/components/customizableui/test/browser_947914_button_addons.js
+++ b/browser/components/customizableui/test/browser_947914_button_addons.js
@@ -2,17 +2,17 @@
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var initialLocation = gBrowser.currentURI.spec;
 var newTab = null;
 
-add_task(function() {
+add_task(function*() {
   info("Check addons button existence and functionality");
 
   yield PanelUI.show();
   info("Menu panel was opened");
 
   let addonsButton = document.getElementById("add-ons-button");
   ok(addonsButton, "Add-ons button exists in Panel Menu");
   addonsButton.click();
@@ -21,13 +21,13 @@ add_task(function() {
   yield waitForCondition(() => gBrowser.currentURI &&
                                gBrowser.currentURI.spec == "about:addons");
 
   let addonsPage = gBrowser.selectedBrowser.contentWindow.document.
                             getElementById("addons-page");
   ok(addonsPage, "Add-ons page was opened");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   gBrowser.addTab(initialLocation);
   gBrowser.removeTab(gBrowser.selectedTab);
   info("Tabs were restored");
 });
--- a/browser/components/customizableui/test/browser_947914_button_copy.js
+++ b/browser/components/customizableui/test/browser_947914_button_copy.js
@@ -2,17 +2,17 @@
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var initialLocation = gBrowser.currentURI.spec;
 var globalClipboard;
 
-add_task(function() {
+add_task(function*() {
   info("Check copy button existence and functionality");
 
   let testText = "copy text test";
 
   gURLBar.focus();
   info("The URL bar was focused");
   yield PanelUI.show();
   info("Menu panel was opened");
@@ -47,17 +47,17 @@ add_task(function() {
 
   if (str.value) {
     str.value.QueryInterface(Ci.nsISupportsString);
     clipboardValue = str.value.data;
   }
   is(clipboardValue, testText, "Data was copied to the clipboard.");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   // clear the clipboard
   Services.clipboard.emptyClipboard(globalClipboard);
   info("Clipboard was cleared");
 
   // restore the tab as it was at the begining of the test
   gBrowser.addTab(initialLocation);
   gBrowser.removeTab(gBrowser.selectedTab);
   info("Tabs were restored");
--- a/browser/components/customizableui/test/browser_947914_button_cut.js
+++ b/browser/components/customizableui/test/browser_947914_button_cut.js
@@ -2,17 +2,17 @@
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var initialLocation = gBrowser.currentURI.spec;
 var globalClipboard;
 
-add_task(function() {
+add_task(function*() {
   info("Check cut button existence and functionality");
 
   let testText = "cut text test";
 
   gURLBar.focus();
   yield PanelUI.show();
   info("Menu panel was opened");
 
@@ -45,17 +45,17 @@ add_task(function() {
 
   if (str.value) {
     str.value.QueryInterface(Ci.nsISupportsString);
     clipboardValue = str.value.data;
   }
   is(clipboardValue, testText, "Data was copied to the clipboard.");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   // clear the clipboard
   Services.clipboard.emptyClipboard(globalClipboard);
   info("Clipboard was cleared");
 
   // restore the tab as it was at the begining of the test
   gBrowser.addTab(initialLocation);
   gBrowser.removeTab(gBrowser.selectedTab);
   info("Tabs were restored");
--- a/browser/components/customizableui/test/browser_947914_button_find.js
+++ b/browser/components/customizableui/test/browser_947914_button_find.js
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-add_task(function() {
+add_task(function*() {
   info("Check find button existence and functionality");
 
   yield PanelUI.show();
   info("Menu panel was opened");
 
   let findButton = document.getElementById("find-button");
   ok(findButton, "Find button exists in Panel Menu");
 
--- a/browser/components/customizableui/test/browser_947914_button_history.js
+++ b/browser/components/customizableui/test/browser_947914_button_history.js
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-add_task(function() {
+add_task(function*() {
   info("Check history button existence and functionality");
 
   yield PanelUI.show();
   info("Menu panel was opened");
 
   let historyButton = document.getElementById("history-panelmenu");
   ok(historyButton, "History button appears in Panel Menu");
 
--- a/browser/components/customizableui/test/browser_947914_button_newPrivateWindow.js
+++ b/browser/components/customizableui/test/browser_947914_button_newPrivateWindow.js
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-add_task(function() {
+add_task(function*() {
   info("Check private browsing button existence and functionality");
 
   yield PanelUI.show();
   info("Menu panel was opened");
 
   let windowWasHandled = false;
   let privateWindow = null;
 
--- a/browser/components/customizableui/test/browser_947914_button_newWindow.js
+++ b/browser/components/customizableui/test/browser_947914_button_newWindow.js
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-add_task(function() {
+add_task(function*() {
   info("Check new window button existence and functionality");
   yield PanelUI.show();
   info("Menu panel was opened");
 
   let windowWasHandled = false;
   let newWindow = null;
 
   let observerWindowOpened = {
--- a/browser/components/customizableui/test/browser_947914_button_paste.js
+++ b/browser/components/customizableui/test/browser_947914_button_paste.js
@@ -2,17 +2,17 @@
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var initialLocation = gBrowser.currentURI.spec;
 var globalClipboard;
 
-add_task(function() {
+add_task(function*() {
   info("Check paste button existence and functionality");
 
   let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
   globalClipboard = Services.clipboard.kGlobalClipboard;
 
   yield PanelUI.show();
   info("Menu panel was opened");
 
@@ -29,17 +29,17 @@ add_task(function() {
   info("Menu panel was opened");
 
   ok(!pasteButton.hasAttribute("disabled"), "Paste button is enabled");
   pasteButton.click();
 
   is(gURLBar.value, text, "Text pasted successfully");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   // clear the clipboard
   Services.clipboard.emptyClipboard(globalClipboard);
   info("Clipboard was cleared");
 
   // restore the tab as it was at the begining of the test
   gBrowser.addTab(initialLocation);
   gBrowser.removeTab(gBrowser.selectedTab);
   info("Tabs were restored");
--- a/browser/components/customizableui/test/browser_947914_button_print.js
+++ b/browser/components/customizableui/test/browser_947914_button_print.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const isOSX = (Services.appinfo.OS === "Darwin");
 
-add_task(function() {
+add_task(function*() {
   info("Check print button existence and functionality");
 
   yield PanelUI.show();
   info("Menu panel was opened");
 
   yield waitForCondition(() => document.getElementById("print-button") != null);
 
   let printButton = document.getElementById("print-button");
@@ -26,16 +26,16 @@ add_task(function() {
   else {
     printButton.click();
     yield waitForCondition(() => gInPrintPreviewMode);
 
     ok(gInPrintPreviewMode, "Entered print preview mode");
   }
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
     // close print preview
     if (gInPrintPreviewMode) {
       PrintUtils.exitPrintPreview();
       yield waitForCondition(() => !window.gInPrintPreviewMode);
       info("Exited print preview")
     }
 });
--- a/browser/components/customizableui/test/browser_947914_button_savePage.js
+++ b/browser/components/customizableui/test/browser_947914_button_savePage.js
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-add_task(function() {
+add_task(function*() {
   info("Check save page button existence");
 
   yield PanelUI.show();
   info("Menu panel was opened");
 
   let savePageButton = document.getElementById("save-page-button");
   ok(savePageButton, "Save Page button exists in Panel Menu");
 
--- a/browser/components/customizableui/test/browser_947914_button_zoomIn.js
+++ b/browser/components/customizableui/test/browser_947914_button_zoomIn.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var initialPageZoom = ZoomManager.zoom;
 
-add_task(function() {
+add_task(function*() {
   info("Check zoom in button existence and functionality");
 
   is(initialPageZoom, 1, "Initial zoom factor should be 1");
 
   yield PanelUI.show();
   info("Menu panel was opened");
 
   let zoomInButton = document.getElementById("zoom-in-button");
@@ -25,13 +25,13 @@ add_task(function() {
 
   // close the Panel
   let panelHiddenPromise = promisePanelHidden(window);
   PanelUI.hide();
   yield panelHiddenPromise;
   info("Menu panel was closed");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   // reset zoom level
   ZoomManager.zoom = initialPageZoom;
   info("Zoom level was restored");
 });
--- a/browser/components/customizableui/test/browser_947914_button_zoomOut.js
+++ b/browser/components/customizableui/test/browser_947914_button_zoomOut.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var initialPageZoom = ZoomManager.zoom;
 
-add_task(function() {
+add_task(function*() {
   info("Check zoom out button existence and functionality");
 
   is(initialPageZoom, 1, "Initial zoom factor should be 1");
 
   yield PanelUI.show();
   info("Menu panel was opened");
 
   let zoomOutButton = document.getElementById("zoom-out-button");
@@ -26,13 +26,13 @@ add_task(function() {
 
   // close the panel
   let panelHiddenPromise = promisePanelHidden(window);
   PanelUI.hide();
   yield panelHiddenPromise;
   info("Menu panel was closed");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   // reset zoom level
   ZoomManager.zoom = initialPageZoom;
   info("Zoom level was restored");
 });
--- a/browser/components/customizableui/test/browser_947914_button_zoomReset.js
+++ b/browser/components/customizableui/test/browser_947914_button_zoomReset.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var initialPageZoom = ZoomManager.zoom;
 
-add_task(function() {
+add_task(function*() {
   info("Check zoom reset button existence and functionality");
 
   is(initialPageZoom, 1, "Page zoom reset correctly");
   ZoomManager.zoom = 0.5;
   yield PanelUI.show();
   info("Menu panel was opened");
 
   let zoomResetButton = document.getElementById("zoom-reset-button");
@@ -26,13 +26,13 @@ add_task(function() {
 
   // close the panel
   let panelHiddenPromise = promisePanelHidden(window);
   PanelUI.hide();
   yield panelHiddenPromise;
   info("Menu panel was closed");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   // reset zoom level
   ZoomManager.zoom = initialPageZoom;
   info("Zoom level was restored");
 });
--- a/browser/components/customizableui/test/browser_947987_removable_default.js
+++ b/browser/components/customizableui/test/browser_947987_removable_default.js
@@ -18,17 +18,17 @@ add_task(function() {
 
   // Widget without removable set should be removable:
   let wrapper = CustomizableUI.createWidget({id: kWidgetId + (widgetCounter++)});
   ok(CustomizableUI.isWidgetRemovable(wrapper.id), "Should be removable by default.");
   CustomizableUI.destroyWidget(wrapper.id);
 });
 
 // Test non-removable widget with defaultArea
-add_task(function() {
+add_task(function*() {
   // Non-removable widget with defaultArea should work:
   let spec = {id: kWidgetId + (widgetCounter++), removable: false,
               defaultArea: kNavBar};
   let widgetWrapper;
   try {
     widgetWrapper = CustomizableUI.createWidget(spec);
   } catch (ex) {
     ok(false, "Creating a non-removable widget with a default area should not throw.");
@@ -58,11 +58,11 @@ add_task(function() {
       is(singleWrapper.node.parentNode, expectedParent,
          "Widget should be in navbar in other window.");
     }
   }
   CustomizableUI.destroyWidget(spec.id);
   yield promiseWindowClosed(otherWin);
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_952963_areaType_getter_no_area.js
+++ b/browser/components/customizableui/test/browser_952963_areaType_getter_no_area.js
@@ -14,17 +14,17 @@ function checkAreaType(widget) {
     is(widget.areaType, null, "areaType should be null");
   } catch (ex) {
     info("Fetching areaType threw: " + ex);
     ok(false, "areaType getter shouldn't throw.");
   }
 }
 
 // widget wrappers in unregisterArea'd areas and nowhere shouldn't throw when checking areaTypes.
-add_task(function() {
+add_task(function*() {
   // Using the ID before it's been created will imply a XUL wrapper; we'll test
   // an API-based wrapper below
   let toolbarNode = createToolbarWithPlacements(kToolbarName, [kUnregisterAreaTestWidget]);
   CustomizableUI.unregisterArea(kToolbarName);
   toolbarNode.remove();
 
   let w = CustomizableUI.getWidget(kUnregisterAreaTestWidget);
   checkAreaType(w);
@@ -41,12 +41,12 @@ add_task(function() {
   w = CustomizableUI.getWidget(spec.id);
   checkAreaType(w);
   CustomizableUI.removeWidgetFromArea(kUnregisterAreaTestWidget);
   checkAreaType(w);
   //XXXgijs: ensure cleanup function doesn't barf:
   gAddedToolbars.delete(kToolbarName);
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
 
--- a/browser/components/customizableui/test/browser_956602_remove_special_widget.js
+++ b/browser/components/customizableui/test/browser_956602_remove_special_widget.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 
 // Adding a separator and then dragging it out of the navbar shouldn't throw
-add_task(function() {
+add_task(function*() {
   try {
     let navbar = document.getElementById("nav-bar");
     let separatorSelector = "toolbarseparator[id^=customizableui-special-separator]";
     ok(!navbar.querySelector(separatorSelector), "Shouldn't be a separator in the navbar");
     CustomizableUI.addWidgetToArea('separator', 'nav-bar');
     yield startCustomizing();
     let separator = navbar.querySelector(separatorSelector);
     ok(separator, "There should be a separator in the navbar now.");
@@ -21,11 +21,11 @@ add_task(function() {
   } catch (ex) {
     Cu.reportError(ex);
     ok(false, "Shouldn't throw an exception moving an item to the navbar.");
   } finally {
     yield endCustomizing();
   }
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_962884_opt_in_disable_hyphens.js
+++ b/browser/components/customizableui/test/browser_962884_opt_in_disable_hyphens.js
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-add_task(function() {
+add_task(function*() {
   const kNormalLabel = "Character Encoding";
   CustomizableUI.addWidgetToArea("characterencoding-button", CustomizableUI.AREA_NAVBAR);
   let characterEncoding = document.getElementById("characterencoding-button");
   const kOriginalLabel = characterEncoding.getAttribute("label");
   characterEncoding.setAttribute("label", "\u00ad" + kNormalLabel);
   CustomizableUI.addWidgetToArea("characterencoding-button", CustomizableUI.AREA_PANEL);
 
   yield PanelUI.show();
@@ -56,12 +56,12 @@ add_task(function() {
 
   CustomizableUI.addWidgetToArea("characterencoding-button", CustomizableUI.AREA_NAVBAR);
   ok(!characterEncoding.hasAttribute("auto-hyphens"),
      "Removing the widget from the panel should remove the auto-hyphens attribute");
 
   characterEncoding.setAttribute("label", kOriginalLabel);
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield endCustomizing();
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_963639_customizing_attribute_non_customizable_toolbar.js
+++ b/browser/components/customizableui/test/browser_963639_customizing_attribute_non_customizable_toolbar.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const kToolbar = "test-toolbar-963639-non-customizable-customizing-attribute";
 
-add_task(function() {
+add_task(function*() {
   info("Test for Bug 963639 - CustomizeMode _onToolbarVisibilityChange sets @customizing on non-customizable toolbars");
 
   let toolbar = document.createElement("toolbar");
   toolbar.id = kToolbar;
   gNavToolbox.appendChild(toolbar);
 
   let testToolbar = document.getElementById(kToolbar)
   ok(testToolbar, "Toolbar was created.");
--- a/browser/components/customizableui/test/browser_967000_button_charEncoding.js
+++ b/browser/components/customizableui/test/browser_967000_button_charEncoding.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 const TEST_PAGE = "http://mochi.test:8888/browser/browser/components/customizableui/test/support/test_967000_charEncoding_page.html";
 
 var newTab;
 var initialLocation = gBrowser.currentURI.spec;
 
-add_task(function() {
+add_task(function*() {
   info("Check Character Encoding button functionality");
 
   // add the Character Encoding button to the panel
   CustomizableUI.addWidgetToArea("characterencoding-button",
                                   CustomizableUI.AREA_PANEL);
 
   // check the button's functionality
   yield PanelUI.show();
@@ -50,17 +50,17 @@ add_task(function() {
      1,
      "There should be 1 checked detector.");
 
   panelHidePromise = promisePanelHidden(window);
   PanelUI.hide();
   yield panelHidePromise;
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   // reset the panel to the default state
   yield resetCustomization();
   ok(CustomizableUI.inDefaultState, "The UI is in default state again.");
 
   // restore the initial location
   gBrowser.addTab(initialLocation);
   gBrowser.removeTab(newTab);
 });
--- a/browser/components/customizableui/test/browser_967000_button_feeds.js
+++ b/browser/components/customizableui/test/browser_967000_button_feeds.js
@@ -5,17 +5,17 @@
 "use strict";
 
 const TEST_PAGE = "http://mochi.test:8888/browser/browser/components/customizableui/test/support/feeds_test_page.html";
 const TEST_FEED = "http://mochi.test:8888/browser/browser/components/customizableui/test/support/test-feed.xml"
 
 var newTab = null;
 var initialLocation = gBrowser.currentURI.spec;
 
-add_task(function() {
+add_task(function*() {
   info("Check Subscribe button functionality");
 
   // add the Subscribe button to the panel
   CustomizableUI.addWidgetToArea("feed-button",
                                   CustomizableUI.AREA_PANEL);
 
   // check the button's functionality
   yield PanelUI.show();
@@ -44,17 +44,17 @@ add_task(function() {
 
   if(isPanelUIOpen()) {
     panelHidePromise = promisePanelHidden(window);
     PanelUI.hide();
     yield panelHidePromise;
   }
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   // reset the panel UI to the default state
   yield resetCustomization();
   ok(CustomizableUI.inDefaultState, "The UI is in default state again.");
 
   // restore the initial location
   gBrowser.addTab(initialLocation);
   gBrowser.removeTab(newTab);
 });
--- a/browser/components/customizableui/test/browser_967000_button_sync.js
+++ b/browser/components/customizableui/test/browser_967000_button_sync.js
@@ -41,17 +41,17 @@ add_task(function* setup() {
   SyncedTabs._internal = mockedInternal;
 
   registerCleanupFunction(() => {
     SyncedTabs._internal = oldInternal;
   });
 });
 
 // The test expects the about:preferences#sync page to open in the current tab
-function openPrefsFromMenuPanel(expectedPanelId, entryPoint) {
+function* openPrefsFromMenuPanel(expectedPanelId, entryPoint) {
   info("Check Sync button functionality");
   Services.prefs.setCharPref("identity.fxaccounts.remote.signup.uri", "http://example.com/");
 
   // add the Sync button to the panel
   CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
 
   // check the button's functionality
   yield PanelUI.show();
@@ -97,17 +97,17 @@ function openPrefsFromMenuPanel(expected
 
   if(isPanelUIOpen()) {
     let panelHidePromise = promisePanelHidden(window);
     PanelUI.hide();
     yield panelHidePromise;
   }
 }
 
-function asyncCleanup() {
+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);
--- a/browser/components/customizableui/test/browser_968447_bookmarks_toolbar_items_in_panel.js
+++ b/browser/components/customizableui/test/browser_968447_bookmarks_toolbar_items_in_panel.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Bug 968447 - The Bookmarks Toolbar Items doesn't appear as a
 // normal menu panel button in new windows.
-add_task(function() {
+add_task(function*() {
   const buttonId = "bookmarks-toolbar-placeholder";
   yield startCustomizing();
   CustomizableUI.addWidgetToArea("personal-bookmarks", CustomizableUI.AREA_PANEL);
   yield endCustomizing();
 
   yield PanelUI.show();
 
   let bookmarksToolbarPlaceholder = document.getElementById(buttonId);
@@ -53,13 +53,13 @@ add_task(function() {
   } else {
     info("panel was already closed");
   }
 
   info("Waiting for new window to close");
   yield promiseWindowClosed(newWin);
 });
 
-add_task(function asyncCleanUp() {
+add_task(function* asyncCleanUp() {
   yield endCustomizing();
   CustomizableUI.reset();
 });
 
--- a/browser/components/customizableui/test/browser_968565_insert_before_hidden_items.js
+++ b/browser/components/customizableui/test/browser_968565_insert_before_hidden_items.js
@@ -7,17 +7,17 @@
 const kHidden1Id = "test-hidden-button-1";
 const kHidden2Id = "test-hidden-button-2";
 
 var navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
 
 // When we drag an item onto a customizable area, and not over a specific target, we
 // should assume that we're appending them to the area. If doing so, we should scan
 // backwards over any hidden items and insert the item before those hidden items.
-add_task(function() {
+add_task(function*() {
   ok(CustomizableUI.inDefaultState, "Should be in the default state");
 
   // Iterate backwards over the items in the nav-bar until we find the first
   // one that is not hidden.
   let placements = CustomizableUI.getWidgetsInArea(CustomizableUI.AREA_NAVBAR);
   let lastVisible = null;
   for (let widgetGroup of placements.reverse()) {
     let widget = widgetGroup.forWindow(window);
--- a/browser/components/customizableui/test/browser_969661_character_encoding_navbar_disabled.js
+++ b/browser/components/customizableui/test/browser_969661_character_encoding_navbar_disabled.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 
 // Adding the character encoding menu to the panel, exiting customize mode,
 // and moving it to the nav-bar should have it enabled, not disabled.
-add_task(function() {
+add_task(function*() {
   yield startCustomizing();
   CustomizableUI.addWidgetToArea("characterencoding-button", "PanelUI-contents");
   yield endCustomizing();
   yield PanelUI.show();
   let panelHiddenPromise = promisePanelHidden(window);
   PanelUI.hide();
   yield panelHiddenPromise;
   CustomizableUI.addWidgetToArea("characterencoding-button", 'nav-bar');
--- a/browser/components/customizableui/test/browser_970511_undo_restore_default.js
+++ b/browser/components/customizableui/test/browser_970511_undo_restore_default.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 requestLongerTimeout(2);
 
 // Restoring default should show an "undo" option which undoes the restoring operation.
-add_task(function() {
+add_task(function*() {
   let homeButtonId = "home-button";
   CustomizableUI.removeWidgetFromArea(homeButtonId);
   yield startCustomizing();
   ok(!CustomizableUI.inDefaultState, "Not in default state to begin with");
   is(CustomizableUI.getPlacementOfWidget(homeButtonId), null, "Home button is in palette");
   let undoResetButton = document.getElementById("customization-undo-reset-button");
   is(undoResetButton.hidden, true, "The undo button is hidden before reset");
 
@@ -26,17 +26,17 @@ add_task(function() {
   ok(!CustomizableUI.inDefaultState, "Not in default state after reset-undo");
   is(undoResetButton.hidden, true, "The undo button is hidden after clicking on the undo button");
   is(CustomizableUI.getPlacementOfWidget(homeButtonId), null, "Home button is in palette");
 
   yield gCustomizeMode.reset();
 });
 
 // Performing an action after a reset will hide the reset button.
-add_task(function() {
+add_task(function*() {
   let homeButtonId = "home-button";
   CustomizableUI.removeWidgetFromArea(homeButtonId);
   ok(!CustomizableUI.inDefaultState, "Not in default state to begin with");
   is(CustomizableUI.getPlacementOfWidget(homeButtonId), null, "Home button is in palette");
   let undoResetButton = document.getElementById("customization-undo-reset-button");
   is(undoResetButton.hidden, true, "The undo button is hidden before reset");
 
   yield gCustomizeMode.reset();
@@ -44,30 +44,30 @@ add_task(function() {
   ok(CustomizableUI.inDefaultState, "In default state after reset");
   is(undoResetButton.hidden, false, "The undo button is visible after reset");
 
   CustomizableUI.addWidgetToArea(homeButtonId, CustomizableUI.AREA_PANEL);
   is(undoResetButton.hidden, true, "The undo button is hidden after another change");
 });
 
 // "Restore defaults", exiting customize, and re-entering shouldn't show the Undo button
-add_task(function() {
+add_task(function*() {
   let undoResetButton = document.getElementById("customization-undo-reset-button");
   is(undoResetButton.hidden, true, "The undo button is hidden before a reset");
   ok(!CustomizableUI.inDefaultState, "The browser should not be in default state");
   yield gCustomizeMode.reset();
 
   is(undoResetButton.hidden, false, "The undo button is visible after a reset");
   yield endCustomizing();
   yield startCustomizing();
   is(undoResetButton.hidden, true, "The undo reset button should be hidden after entering customization mode");
 });
 
 // Bug 971626 - Restore Defaults should collapse the Title Bar
-add_task(function() {
+add_task(function*() {
   if (Services.appinfo.OS != "WINNT" &&
       Services.appinfo.OS != "Darwin") {
     return;
   }
   let prefName = "browser.tabs.drawInTitlebar";
   let defaultValue = Services.prefs.getBoolPref(prefName);
   let restoreDefaultsButton = document.getElementById("customization-reset-button");
   let titleBarButton = document.getElementById("customization-titlebar-visibility-button");
@@ -98,12 +98,12 @@ add_task(function() {
   is(Services.prefs.getBoolPref(prefName), !defaultValue, "Undo-reset goes back to previous pref value");
   is(undoResetButton.hidden, true, "Undo reset button should be hidden after undo-reset clicked");
 
   Services.prefs.clearUserPref(prefName);
   ok(CustomizableUI.inDefaultState, "In default state after pref cleared");
   is(undoResetButton.hidden, true, "Undo reset button should be hidden at end of test");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield gCustomizeMode.reset();
   yield endCustomizing();
 });
--- a/browser/components/customizableui/test/browser_972267_customizationchange_events.js
+++ b/browser/components/customizableui/test/browser_972267_customizationchange_events.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Create a new window, then move the home button to the menu and check both windows have
 // customizationchange events fire on the toolbox:
-add_task(function() {
+add_task(function*() {
   let newWindow = yield openAndLoadWindow();
   let otherToolbox = newWindow.gNavToolbox;
 
   let handlerCalledCount = 0;
   let handler = (ev) => {
     handlerCalledCount++;
   };
 
@@ -36,12 +36,11 @@ add_task(function() {
   is(handlerCalledCount, 2, "Should be called for both windows.");
 
   gNavToolbox.removeEventListener("customizationchange", handler);
   otherToolbox.removeEventListener("customizationchange", handler);
 
   yield promiseWindowClosed(newWindow);
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
-
--- a/browser/components/customizableui/test/browser_973641_button_addon.js
+++ b/browser/components/customizableui/test/browser_973641_button_addon.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const kButton = "test_button_for_addon";
 var initialLocation = gBrowser.currentURI.spec;
 
-add_task(function() {
+add_task(function*() {
   info("Check addon button functionality");
 
   // create mocked addon button on the navigation bar
   let widgetSpec = {
     id: kButton,
     type: 'button',
     onClick: function() {
       gBrowser.selectedTab = gBrowser.addTab("about:addons");
@@ -38,17 +38,17 @@ add_task(function() {
   // check the addon button's functionality in the Panel Menu
   yield PanelUI.show();
   var panelMenu = document.getElementById("PanelUI-mainView");
   let addonButtonInPanel = panelMenu.getElementsByAttribute("id", kButton);
   ok(panelMenu.contains(addonButton), "Addon button was added to the Panel Menu");
   yield checkButtonFunctionality(addonButtonInPanel[0]);
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   resetTabs();
 
   // reset the UI to the default state
   yield resetCustomization();
   ok(CustomizableUI.inDefaultState, "The UI is in default state again.");
 
   // destroy the widget
   CustomizableUI.destroyWidget(kButton);
@@ -60,13 +60,13 @@ function resetTabs() {
     gBrowser.removeTab(gBrowser.selectedTab);
   }
 
   //restore the initial tab
   gBrowser.addTab(initialLocation);
   gBrowser.removeTab(gBrowser.selectedTab);
 }
 
-function checkButtonFunctionality(aButton) {
+function* checkButtonFunctionality(aButton) {
   aButton.click();
   yield waitForCondition(() => gBrowser.currentURI &&
                                gBrowser.currentURI.spec == "about:addons");
 }
--- a/browser/components/customizableui/test/browser_973932_addonbar_currentset.js
+++ b/browser/components/customizableui/test/browser_973932_addonbar_currentset.js
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var addonbarID = CustomizableUI.AREA_ADDONBAR;
 var addonbar = document.getElementById(addonbarID);
 
 // Check that currentset is correctly updated after a reset:
-add_task(function() {
+add_task(function*() {
   let placements = CustomizableUI.getWidgetIdsInArea(addonbarID);
   is(placements.join(','), addonbar.getAttribute("currentset"), "Addon-bar currentset should match default placements");
   ok(CustomizableUI.inDefaultState, "Should be in default state");
   info("Adding a spring to add-on bar shim");
   CustomizableUI.addWidgetToArea("spring", addonbarID, 1);
   ok(addonbar.getElementsByTagName("toolbarspring").length, "There should be a spring in the toolbar");
   ok(!CustomizableUI.inDefaultState, "Should no longer be in default state");
   placements = CustomizableUI.getWidgetIdsInArea(addonbarID);
--- a/browser/components/customizableui/test/browser_975719_customtoolbars_behaviour.js
+++ b/browser/components/customizableui/test/browser_975719_customtoolbars_behaviour.js
@@ -8,17 +8,17 @@ requestLongerTimeout(2);
 
 const kXULWidgetId = "a-test-button"; // we'll create a button with this ID.
 
 add_task(function setup() {
   // create a XUL button and add it to the palette.
   createDummyXULButton(kXULWidgetId, "test-button");
 });
 
-add_task(function customizeToolbarAndKeepIt() {
+add_task(function* customizeToolbarAndKeepIt() {
   ok(gNavToolbox.toolbarset, "There should be a toolbarset");
   let toolbarID = "testAustralisCustomToolbar";
   gNavToolbox.appendCustomToolbar(toolbarID, "");
   let toolbarDOMID = getToolboxCustomToolbarId(toolbarID);
   let toolbarElement = document.getElementById(toolbarDOMID);
   ok(toolbarElement, "There should be a toolbar");
   if (!toolbarElement) {
     ok(false, "No toolbar created, bailing out of the test.");
@@ -79,17 +79,17 @@ add_task(function customizeToolbarAndKee
      "Attribute should be gone in new window");
   yield promiseWindowClosed(newWindow);
 
   ok(!toolbarElement.parentNode, "Toolbar should no longer be in the DOM.");
   cuiAreaType = CustomizableUI.getAreaType(toolbarDOMID);
   is(cuiAreaType, null, "CustomizableUI should have forgotten all about the area");
 });
 
-add_task(function resetShouldDealWithCustomToolbars() {
+add_task(function* resetShouldDealWithCustomToolbars() {
   ok(gNavToolbox.toolbarset, "There should be a toolbarset");
   let toolbarID = "testAustralisCustomToolbar";
   gNavToolbox.appendCustomToolbar(toolbarID, "");
   let toolbarDOMID = getToolboxCustomToolbarId(toolbarID);
   let toolbarElement = document.getElementById(toolbarDOMID);
   ok(toolbarElement, "There should be a toolbar");
   if (!toolbarElement) {
     ok(false, "No toolbar created, bailing out of the test.");
@@ -132,14 +132,14 @@ add_task(function resetShouldDealWithCus
   ok(gNavToolbox.palette.querySelector(`#${kXULWidgetId}`), "XUL button should be in the palette");
   ok(!toolbarElement.hasChildNodes(), "Toolbar should have no more child nodes.");
   ok(!toolbarElement.parentNode, "Toolbar should no longer be in the DOM.");
   cuiAreaType = CustomizableUI.getAreaType(toolbarDOMID);
   is(cuiAreaType, null, "CustomizableUI should have forgotten all about the area");
 });
 
 
-add_task(function() {
+add_task(function*() {
   let newWin = yield openAndLoadWindow({}, true);
   ok(!newWin.gNavToolbox.toolbarset.hasAttribute("toolbar1"), "New window shouldn't have attribute toolbar1");
   ok(!newWin.gNavToolbox.toolbarset.hasAttribute("toolbar2"), "New window shouldn't have attribute toolbar2");
   yield promiseWindowClosed(newWin);
 });
--- a/browser/components/customizableui/test/browser_976792_insertNodeInWindow.js
+++ b/browser/components/customizableui/test/browser_976792_insertNodeInWindow.js
@@ -8,17 +8,17 @@ const kToolbarName = "test-insertNodeInW
 const kTestWidgetPrefix = "test-widget-for-insertNodeInWindow-placements-";
 
 
 /*
 Tries to replicate the situation of having a placement list like this:
 
 exists-1,trying-to-insert-this,doesn't-exist,exists-2
 */
-add_task(function() {
+add_task(function*() {
   let testWidgetExists = [true, false, false, true];
   let widgetIds = [];
   for (let i = 0; i < testWidgetExists.length; i++) {
     let id = kTestWidgetPrefix + i;
     widgetIds.push(id);
     if (testWidgetExists[i]) {
       let spec = {id: id, type: "button", removable: true, label: "test", tooltiptext: "" + i};
       CustomizableUI.createWidget(spec);
@@ -45,17 +45,17 @@ add_task(function() {
 
 
 /*
 Tests nodes get placed inside the toolbar's overflow as expected. Replicates a
 situation similar to:
 
 exists-1,exists-2,overflow-1,trying-to-insert-this,overflow-2
 */
-add_task(function() {
+add_task(function*() {
   let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
 
   let widgetIds = [];
   for (let i = 0; i < 5; i++) {
     let id = kTestWidgetPrefix + i;
     widgetIds.push(id);
     let spec = {id: id, type: "button", removable: true, label: "insertNodeInWindow test", tooltiptext: "" + i};
     CustomizableUI.createWidget(spec);
@@ -94,17 +94,17 @@ add_task(function() {
 
 
 /*
 Tests nodes get placed inside the toolbar's overflow as expected. Replicates a
 placements situation similar to:
 
 exists-1,exists-2,overflow-1,doesn't-exist,trying-to-insert-this,overflow-2
 */
-add_task(function() {
+add_task(function*() {
   let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
 
   let widgetIds = [];
   for (let i = 0; i < 5; i++) {
     let id = kTestWidgetPrefix + i;
     widgetIds.push(id);
     let spec = {id: id, type: "button", removable: true, label: "insertNodeInWindow test", tooltiptext: "" + i};
     CustomizableUI.createWidget(spec);
@@ -144,17 +144,17 @@ add_task(function() {
 
 
 /*
 Tests nodes get placed inside the toolbar's overflow as expected. Replicates a
 placements situation similar to:
 
 exists-1,exists-2,overflow-1,doesn't-exist,trying-to-insert-this,doesn't-exist
 */
-add_task(function() {
+add_task(function*() {
   let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
 
   let widgetIds = [];
   for (let i = 0; i < 5; i++) {
     let id = kTestWidgetPrefix + i;
     widgetIds.push(id);
     let spec = {id: id, type: "button", removable: true, label: "insertNodeInWindow test", tooltiptext: "" + i};
     CustomizableUI.createWidget(spec);
@@ -195,17 +195,17 @@ add_task(function() {
 
 
 /*
 Tests nodes get placed inside the toolbar's overflow as expected. Replicates a
 placements situation similar to:
 
 exists-1,exists-2,overflow-1,can't-overflow,trying-to-insert-this,overflow-2
 */
-add_task(function() {
+add_task(function*() {
   let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
 
   let widgetIds = [];
   for (let i = 5; i >= 0; i--) {
     let id = kTestWidgetPrefix + i;
     widgetIds.push(id);
     let spec = {id: id, type: "button", removable: true, label: "insertNodeInWindow test", tooltiptext: "" + i};
     CustomizableUI.createWidget(spec);
@@ -254,17 +254,17 @@ add_task(function() {
 
 
 /*
 Tests nodes get placed inside the toolbar's overflow as expected. Replicates a
 placements situation similar to:
 
 exists-1,exists-2,overflow-1,trying-to-insert-this,can't-overflow,overflow-2
 */
-add_task(function() {
+add_task(function*() {
   let widgetIds = [];
   let missingId = 2;
   let nonOverflowableId = 3;
   for (let i = 0; i < 5; i++) {
     let id = kTestWidgetPrefix + i;
     widgetIds.push(id);
     if (i != missingId) {
       // Setting min-width to make the overflow state not depend on styling of the button and/or
@@ -311,17 +311,17 @@ add_task(function() {
 
 
 /*
 Tests nodes do *not* get placed in the toolbar's overflow. Replicates a
 plcements situation similar to:
 
 exists-1,trying-to-insert-this,exists-2,overflowed-1
 */
-add_task(function() {
+add_task(function*() {
   let widgetIds = [];
   let missingId = 1;
   for (let i = 0; i < 5; i++) {
     let id = kTestWidgetPrefix + i;
     widgetIds.push(id);
     if (i != missingId) {
       // Setting min-width to make the overflow state not depend on styling of the button and/or
       // screen width
@@ -360,17 +360,17 @@ add_task(function() {
 /*
 Tests inserting a node onto the end of an overflowing toolbar *doesn't* put it in
 the overflow list when the widget disallows overflowing. ie:
 
 exists-1,exists-2,overflows-1,trying-to-insert-this
 
 Where trying-to-insert-this has overflows=false
 */
-add_task(function() {
+add_task(function*() {
   let widgetIds = [];
   let missingId = 3;
   for (let i = 0; i < 5; i++) {
     let id = kTestWidgetPrefix + i;
     widgetIds.push(id);
     if (i != missingId) {
       // Setting min-width to make the overflow state not depend on styling of the button and/or
       // screen width
@@ -404,11 +404,11 @@ add_task(function() {
 
   btn.remove();
   widgetIds.forEach(id => CustomizableUI.destroyWidget(id));
   removeCustomToolbars();
   yield resetCustomization();
 });
 
 
-add_task(function asyncCleanUp() {
+add_task(function* asyncCleanUp() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_978084_dragEnd_after_move.js
+++ b/browser/components/customizableui/test/browser_978084_dragEnd_after_move.js
@@ -5,42 +5,42 @@
 
 var draggedItem;
 
 /**
  * Check that customizing-movingItem gets removed on a drop when the item is moved.
  */
 
 // Drop on the palette
-add_task(function() {
+add_task(function*() {
   draggedItem = document.createElement("toolbarbutton");
   draggedItem.id = "test-dragEnd-after-move1";
   draggedItem.setAttribute("label", "Test");
   draggedItem.setAttribute("removable", "true");
   let navbar = document.getElementById("nav-bar");
   navbar.customizationTarget.appendChild(draggedItem);
   yield startCustomizing();
   simulateItemDrag(draggedItem, gCustomizeMode.visiblePalette);
   is(document.documentElement.hasAttribute("customizing-movingItem"), false,
      "Make sure customizing-movingItem is removed after dragging to the palette");
   yield endCustomizing();
 });
 
 // Drop on a customization target itself
-add_task(function() {
+add_task(function*() {
   draggedItem = document.createElement("toolbarbutton");
   draggedItem.id = "test-dragEnd-after-move2";
   draggedItem.setAttribute("label", "Test");
   draggedItem.setAttribute("removable", "true");
   let dest = createToolbarWithPlacements("test-dragEnd");
   let navbar = document.getElementById("nav-bar");
   navbar.customizationTarget.appendChild(draggedItem);
   yield startCustomizing();
   simulateItemDrag(draggedItem, dest.customizationTarget);
   is(document.documentElement.hasAttribute("customizing-movingItem"), false,
      "Make sure customizing-movingItem is removed");
   yield endCustomizing();
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield endCustomizing();
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_980155_add_overflow_toolbar.js
+++ b/browser/components/customizableui/test/browser_980155_add_overflow_toolbar.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const kToolbarName = "test-new-overflowable-toolbar";
 const kTestWidgetPrefix = "test-widget-for-overflowable-toolbar-";
 
-add_task(function addOverflowingToolbar() {
+add_task(function* addOverflowingToolbar() {
   let originalWindowWidth = window.outerWidth;
 
   let widgetIds = [];
   for (let i = 0; i < 10; i++) {
     let id = kTestWidgetPrefix + i;
     widgetIds.push(id);
     let spec = {id: id, type: "button", removable: true, label: "test", tooltiptext: "" + i};
     CustomizableUI.createWidget(spec);
@@ -40,12 +40,12 @@ add_task(function addOverflowingToolbar(
   ok(toolbarNode.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
   ok(toolbarNode.customizationTarget.childElementCount < oldChildCount, "Should have fewer children.");
   ok(overflowableList.childElementCount > oldOverflowCount, "Should have more overflowed widgets.");
 
   window.resizeTo(originalWindowWidth, window.outerHeight);
 });
 
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   removeCustomToolbars();
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_981305_separator_insertion.js
+++ b/browser/components/customizableui/test/browser_981305_separator_insertion.js
@@ -19,17 +19,17 @@ function insertTempItemsIntoMenu(parentM
     // And another separator for good measure:
     sep = document.createElement("menuseparator");
     tempElements.push(sep);
     parentMenu.insertBefore(sep, beforeEls[i]);
   }
 }
 
 function checkSeparatorInsertion(menuId, buttonId, subviewId) {
-  return function() {
+  return function*() {
     info("Checking for duplicate separators in " + buttonId + " widget");
     let menu = document.getElementById(menuId);
     insertTempItemsIntoMenu(menu);
 
     let placement = CustomizableUI.getPlacementOfWidget(buttonId);
     let changedPlacement = false;
     if (!placement || placement.area != CustomizableUI.AREA_PANEL) {
       CustomizableUI.addWidgetToArea(buttonId, CustomizableUI.AREA_PANEL);
--- a/browser/components/customizableui/test/browser_981418-widget-onbeforecreated-handler.js
+++ b/browser/components/customizableui/test/browser_981418-widget-onbeforecreated-handler.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 const kWidgetId = 'test-981418-widget-onbeforecreated';
 
 // Should be able to add broken view widget
-add_task(function testAddOnBeforeCreatedWidget() {
+add_task(function* testAddOnBeforeCreatedWidget() {
   let viewShownDeferred = Promise.defer();
   let onBeforeCreatedCalled = false;
   let widgetSpec = {
     id: kWidgetId,
     type: 'view',
     viewId: kWidgetId + 'idontexistyet',
     onBeforeCreated: function(doc) {
       let view = doc.createElement("panelview");
@@ -80,11 +80,11 @@ add_task(function testAddOnBeforeCreated
     CustomizableUI.destroyWidget(kWidgetId);
   } catch (ex) {
     Cu.reportError(ex);
     noError = false;
   }
   ok(noError, "Should not throw an exception trying to remove the broken view widget.");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   yield resetCustomization();
 });
--- a/browser/components/customizableui/test/browser_982656_restore_defaults_builtin_widgets.js
+++ b/browser/components/customizableui/test/browser_982656_restore_defaults_builtin_widgets.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Restoring default should not place addon widgets back in the toolbar
-add_task(function() {
+add_task(function*() {
   ok(CustomizableUI.inDefaultState, "Default state to begin");
 
   const kWidgetId = "bug982656-add-on-widget-should-not-restore-to-default-area";
   let widgetSpec = {
     id: kWidgetId,
     defaultArea: CustomizableUI.AREA_NAVBAR
   };
   CustomizableUI.createWidget(widgetSpec);
@@ -22,17 +22,17 @@ add_task(function() {
 
   ok(CustomizableUI.inDefaultState, "Back in default state after reset");
   is(CustomizableUI.getPlacementOfWidget(kWidgetId), null, "Widget now in palette");
   CustomizableUI.destroyWidget(kWidgetId);
 });
 
 
 // resetCustomization shouldn't move 3rd party widgets out of custom toolbars
-add_task(function() {
+add_task(function*() {
   const kToolbarId = "bug982656-toolbar-with-defaultset";
   const kWidgetId = "bug982656-add-on-widget-should-restore-to-default-area-when-area-is-not-builtin";
   ok(CustomizableUI.inDefaultState, "Everything should be in its default state.");
   let toolbar = createToolbarWithPlacements(kToolbarId);
   ok(CustomizableUI.areas.indexOf(kToolbarId) != -1,
      "Toolbar has been registered.");
   is(CustomizableUI.getAreaType(kToolbarId), CustomizableUI.TYPE_TOOLBAR,
      "Area should be registered as toolbar");
--- a/browser/components/customizableui/test/browser_985815_propagate_setToolbarVisibility.js
+++ b/browser/components/customizableui/test/browser_985815_propagate_setToolbarVisibility.js
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-add_task(function() {
+add_task(function*() {
   ok(CustomizableUI.inDefaultState, "Should start in default state.");
   this.otherWin = yield openAndLoadWindow({private: true}, true);
   yield startCustomizing(this.otherWin);
   let resetButton = this.otherWin.document.getElementById("customization-reset-button");
   ok(resetButton.disabled, "Reset button should be disabled");
 
   if (typeof CustomizableUI.setToolbarVisibility == "function") {
     CustomizableUI.setToolbarVisibility("PersonalToolbar", true);
@@ -30,16 +30,16 @@ add_task(function() {
   ok(resetButton.disabled, "Reset button should be disabled");
 
   yield endCustomizing(this.otherWin);
 
   yield promiseWindowClosed(this.otherWin);
 });
 
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   if (this.otherWin && !this.otherWin.closed) {
     yield promiseWindowClosed(this.otherWin);
   }
   if (!CustomizableUI.inDefaultState) {
     CustomizableUI.reset();
   }
 });
--- a/browser/components/customizableui/test/browser_987640_charEncoding.js
+++ b/browser/components/customizableui/test/browser_987640_charEncoding.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const TEST_PAGE = "http://mochi.test:8888/browser/browser/components/customizableui/test/support/test_967000_charEncoding_page.html";
 var newTab = null;
 
-add_task(function() {
+add_task(function*() {
   info("Check Character Encoding panel functionality");
 
   // add the Character Encoding button to the panel
   CustomizableUI.addWidgetToArea("characterencoding-button",
                                   CustomizableUI.AREA_PANEL);
 
   newTab = gBrowser.addTab(TEST_PAGE);
   yield promiseTabLoadEvent(gBrowser.selectedTab, TEST_PAGE);
@@ -47,16 +47,16 @@ add_task(function() {
   initialEncoding.click();
   yield tabLoadPromise;
   yield PanelUI.show();
   charEncodingButton.click();
   checkedButtons = characterEncodingView.querySelectorAll("toolbarbutton[checked='true']");
   is(checkedButtons[0].getAttribute("label"), "Unicode", "The encoding was reset to Unicode");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   // reset the panel to the default state
   yield resetCustomization();
   ok(CustomizableUI.inDefaultState, "The UI is in default state again.");
 
   // remove the added tab
   gBrowser.removeTab(newTab);
 });
--- a/browser/components/customizableui/test/browser_989751_subviewbutton_class.js
+++ b/browser/components/customizableui/test/browser_989751_subviewbutton_class.js
@@ -9,17 +9,17 @@ var tempElement = null;
 
 function insertClassNameToMenuChildren(parentMenu) {
   let el = parentMenu.querySelector("menuitem:first-of-type");
   el.classList.add(kCustomClass);
   tempElement = el;
 }
 
 function checkSubviewButtonClass(menuId, buttonId, subviewId) {
-  return function() {
+  return function*() {
     info("Checking for items without the subviewbutton class in " + buttonId + " widget");
     let menu = document.getElementById(menuId);
     insertClassNameToMenuChildren(menu);
 
     let placement = CustomizableUI.getPlacementOfWidget(buttonId);
     let changedPlacement = false;
     if (!placement || placement.area != CustomizableUI.AREA_PANEL) {
       CustomizableUI.addWidgetToArea(buttonId, CustomizableUI.AREA_PANEL);
--- a/browser/components/customizableui/test/browser_panel_toggle.js
+++ b/browser/components/customizableui/test/browser_panel_toggle.js
@@ -4,34 +4,34 @@
 
 "use strict";
 
 /**
  * Test opening and closing the menu panel UI.
  */
 
 // Show and hide the menu panel programmatically without an event (like UITour.jsm would)
-add_task(function() {
+add_task(function*() {
   let shownPromise = promisePanelShown(window);
   PanelUI.show();
   yield shownPromise;
 
   is(PanelUI.panel.getAttribute("panelopen"), "true", "Check that panel has panelopen attribute");
   is(PanelUI.panel.state, "open", "Check that panel state is 'open'");
 
   let hiddenPromise = promisePanelHidden(window);
   PanelUI.hide();
   yield hiddenPromise;
 
   ok(!PanelUI.panel.hasAttribute("panelopen"), "Check that panel doesn't have the panelopen attribute");
   is(PanelUI.panel.state, "closed", "Check that panel state is 'closed'");
 });
 
 // Toggle the menu panel open and closed
-add_task(function() {
+add_task(function*() {
   let shownPromise = promisePanelShown(window);
   PanelUI.toggle({type: "command"});
   yield shownPromise;
 
   is(PanelUI.panel.getAttribute("panelopen"), "true", "Check that panel has panelopen attribute");
   is(PanelUI.panel.state, "open", "Check that panel state is 'open'");
 
   let hiddenPromise = promisePanelHidden(window);
--- a/browser/components/customizableui/test/head.js
+++ b/browser/components/customizableui/test/head.js
@@ -195,33 +195,33 @@ function endCustomizing(aWindow=window) 
     let deferredLoadNewTab = Promise.defer();
 
     //XXXgijs so some tests depend on this tab being about:blank. Make it so.
     let newTabBrowser = aWindow.gBrowser.selectedBrowser;
     newTabBrowser.stop();
 
     // If we stop early enough, this might actually be about:blank.
     if (newTabBrowser.contentDocument.location.href == "about:blank") {
-      return;
+      return null;
     }
 
     // Otherwise, make it be about:blank, and wait for that to be done.
     function onNewTabLoaded(e) {
       newTabBrowser.removeEventListener("load", onNewTabLoaded, true);
       deferredLoadNewTab.resolve();
     }
     newTabBrowser.addEventListener("load", onNewTabLoaded, true);
     newTabBrowser.contentDocument.location.replace("about:blank");
     return deferredLoadNewTab.promise;
   });
 }
 
 function startCustomizing(aWindow=window) {
   if (aWindow.document.documentElement.getAttribute("customizing") == "true") {
-    return;
+    return null;
   }
   Services.prefs.setBoolPref("browser.uiCustomization.disableAnimation", true);
   let deferred = Promise.defer();
   function onCustomizing() {
     aWindow.gNavToolbox.removeEventListener("customizationready", onCustomizing);
     Services.prefs.setBoolPref("browser.uiCustomization.disableAnimation", false);
     deferred.resolve();
   }
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -31,21 +31,21 @@ XPIDL_SOURCES += [
     'nsIBrowserGlue.idl',
     'nsIBrowserHandler.idl',
 ]
 
 XPIDL_MODULE = 'browsercompsbase'
 
 EXTRA_PP_COMPONENTS += [
     'BrowserComponents.manifest',
-    'nsBrowserGlue.js',
 ]
 
 EXTRA_COMPONENTS += [
     'nsBrowserContentHandler.js',
+    'nsBrowserGlue.js',
 ]
 
 EXTRA_JS_MODULES += [
     'distribution.js',
 ]
 
 BROWSER_CHROME_MANIFESTS += [
     'test/browser.ini'
@@ -54,11 +54,8 @@ BROWSER_CHROME_MANIFESTS += [
 if CONFIG['MOZ_SAFE_BROWSING']:
     BROWSER_CHROME_MANIFESTS += ['safebrowsing/content/test/browser.ini']
 
 with Files('safebrowsing/*'):
     BUG_COMPONENT = ('Toolkit', 'Phishing Protection')
 
 with Files('controlcenter/**'):
     BUG_COMPONENT = ('Firefox', 'General')
-
-if CONFIG['MOZ_REQUIRE_SIGNING']:
-    DEFINES['MOZ_REQUIRE_SIGNING'] = 1
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1,22 +1,22 @@
-# -*- indent-tabs-mode: nil -*-
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cr = Components.results;
 const Cu = Components.utils;
 
 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AboutHome",
                                   "resource:///modules/AboutHome.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AboutNewTab",
                                   "resource:///modules/AboutNewTab.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "DirectoryLinksProvider",
@@ -62,20 +62,20 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource:///modules/CustomizationTabPreloader.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PdfJs",
                                   "resource://pdf.js/PdfJs.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ProcessHangMonitor",
                                   "resource:///modules/ProcessHangMonitor.jsm");
 
-#ifdef NIGHTLY_BUILD
-XPCOMUtils.defineLazyModuleGetter(this, "ShumwayUtils",
-                                  "resource://shumway/ShumwayUtils.jsm");
-#endif
+if (AppConstants.NIGHTLY_BUILD) {
+  XPCOMUtils.defineLazyModuleGetter(this, "ShumwayUtils",
+                                    "resource://shumway/ShumwayUtils.jsm");
+}
 
 XPCOMUtils.defineLazyModuleGetter(this, "webrtcUI",
                                   "resource:///modules/webrtcUI.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
                                   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
@@ -115,35 +115,35 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/AsyncShutdown.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerParent",
                                   "resource://gre/modules/LoginManagerParent.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "SimpleServiceDiscovery",
                                   "resource://gre/modules/SimpleServiceDiscovery.jsm");
 
-#ifdef NIGHTLY_BUILD
-XPCOMUtils.defineLazyModuleGetter(this, "SignInToWebsiteUX",
-                                  "resource:///modules/SignInToWebsite.jsm");
-#endif
+if (AppConstants.NIGHTLY_BUILD) {
+  XPCOMUtils.defineLazyModuleGetter(this, "SignInToWebsiteUX",
+                                    "resource:///modules/SignInToWebsite.jsm");
+}
 
 XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
                                   "resource:///modules/ContentSearch.jsm");
 
-#ifdef E10S_TESTING_ONLY
-XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
-                                  "resource://gre/modules/UpdateUtils.jsm");
-#endif
+if (AppConstants.E10S_TESTING_ONLY) {
+  XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
+                                    "resource://gre/modules/UpdateUtils.jsm");
+}
 
 XPCOMUtils.defineLazyModuleGetter(this, "TabCrashHandler",
                                   "resource:///modules/ContentCrashHandlers.jsm");
-#ifdef MOZ_CRASHREPORTER
-XPCOMUtils.defineLazyModuleGetter(this, "PluginCrashReporter",
-                                  "resource:///modules/ContentCrashHandlers.jsm");
-#endif
+if (AppConstants.MOZ_CRASHREPORTER) {
+  XPCOMUtils.defineLazyModuleGetter(this, "PluginCrashReporter",
+                                    "resource:///modules/ContentCrashHandlers.jsm");
+}
 
 XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
   return Services.strings.createBundle('chrome://branding/locale/brand.properties');
 });
 
 XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
   return Services.strings.createBundle('chrome://browser/locale/browser.properties');
 });
@@ -162,19 +162,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/AddonWatcher.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
                                   "resource://gre/modules/LightweightThemeManager.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
                                   "resource://gre/modules/ExtensionManagement.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
-                                  "resource://gre/modules/AppConstants.jsm");
-
 XPCOMUtils.defineLazyModuleGetter(this, "ShellService",
                                   "resource:///modules/ShellService.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils",
                                    "@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils");
 
 XPCOMUtils.defineLazyServiceGetter(this, "AlertsService",
                                    "@mozilla.org/alerts-service;1", "nsIAlertsService");
@@ -219,21 +216,21 @@ function BrowserGlue() {
       let sanitizerScope = {};
       Services.scriptloader.loadSubScript("chrome://browser/content/sanitize.js", sanitizerScope);
       return sanitizerScope.Sanitizer;
     });
 
   this._init();
 }
 
-#ifndef XP_MACOSX
-# OS X has the concept of zero-window sessions and therefore ignores the
-# browser-lastwindow-close-* topics.
-#define OBSERVE_LASTWINDOW_CLOSE_TOPICS 1
-#endif
+/*
+ * OS X has the concept of zero-window sessions and therefore ignores the
+ * browser-lastwindow-close-* topics.
+ */
+const OBSERVE_LASTWINDOW_CLOSE_TOPICS = AppConstants.platform != "macosx";
 
 BrowserGlue.prototype = {
   _saveSession: false,
   _isPlacesInitObserver: false,
   _isPlacesLockedObserver: false,
   _isPlacesShutdownObserver: false,
   _isPlacesDatabaseLocked: false,
   _migrationImportsDefaultBookmarks: false,
@@ -300,26 +297,28 @@ BrowserGlue.prototype = {
         this._onSafeModeRestart();
         break;
       case "quit-application-requested":
         this._onQuitRequest(subject, data);
         break;
       case "quit-application-granted":
         this._onQuitApplicationGranted();
         break;
-#ifdef OBSERVE_LASTWINDOW_CLOSE_TOPICS
       case "browser-lastwindow-close-requested":
-        // The application is not actually quitting, but the last full browser
-        // window is about to be closed.
-        this._onQuitRequest(subject, "lastwindow");
+        if (OBSERVE_LASTWINDOW_CLOSE_TOPICS) {
+          // The application is not actually quitting, but the last full browser
+          // window is about to be closed.
+          this._onQuitRequest(subject, "lastwindow");
+        }
         break;
       case "browser-lastwindow-close-granted":
-        this._setPrefToSaveSession();
+        if (OBSERVE_LASTWINDOW_CLOSE_TOPICS) {
+          this._setPrefToSaveSession();
+        }
         break;
-#endif
       case "weave:service:ready":
         this._setSyncAutoconnectDelay();
         break;
       case "weave:engine:clients:display-uri":
         this._onDisplaySyncURI(subject);
         break;
       case "session-save":
         this._setPrefToSaveSession(true);
@@ -515,35 +514,35 @@ BrowserGlue.prototype = {
     os.addObserver(this, "notifications-open-settings", false);
     os.addObserver(this, "prefservice:after-app-defaults", false);
     os.addObserver(this, "final-ui-startup", false);
     os.addObserver(this, "browser-delayed-startup-finished", false);
     os.addObserver(this, "sessionstore-windows-restored", false);
     os.addObserver(this, "browser:purge-session-history", false);
     os.addObserver(this, "quit-application-requested", false);
     os.addObserver(this, "quit-application-granted", false);
-#ifdef OBSERVE_LASTWINDOW_CLOSE_TOPICS
-    os.addObserver(this, "browser-lastwindow-close-requested", false);
-    os.addObserver(this, "browser-lastwindow-close-granted", false);
-#endif
+    if (OBSERVE_LASTWINDOW_CLOSE_TOPICS) {
+      os.addObserver(this, "browser-lastwindow-close-requested", false);
+      os.addObserver(this, "browser-lastwindow-close-granted", false);
+    }
     os.addObserver(this, "weave:service:ready", false);
     os.addObserver(this, "weave:engine:clients:display-uri", false);
     os.addObserver(this, "session-save", false);
     os.addObserver(this, "places-init-complete", false);
     this._isPlacesInitObserver = true;
     os.addObserver(this, "places-database-locked", false);
     this._isPlacesLockedObserver = true;
     os.addObserver(this, "distribution-customization-complete", false);
     os.addObserver(this, "places-shutdown", false);
     this._isPlacesShutdownObserver = true;
     os.addObserver(this, "handle-xul-text-link", false);
     os.addObserver(this, "profile-before-change", false);
-#ifdef MOZ_SERVICES_HEALTHREPORT
-    os.addObserver(this, "keyword-search", false);
-#endif
+    if (AppConstants.MOZ_SERVICES_HEALTHREPORT) {
+      os.addObserver(this, "keyword-search", false);
+    }
     os.addObserver(this, "browser-search-engine-modified", false);
     os.addObserver(this, "restart-in-safe-mode", false);
     os.addObserver(this, "flash-plugin-hang", false);
     os.addObserver(this, "xpi-signature-changed", false);
     os.addObserver(this, "autocomplete-did-enter-text", false);
 
     ExtensionManagement.registerScript("chrome://browser/content/ext-utils.js");
     ExtensionManagement.registerScript("chrome://browser/content/ext-browserAction.js");
@@ -571,38 +570,38 @@ BrowserGlue.prototype = {
     os.removeObserver(this, "notifications-open-settings");
     os.removeObserver(this, "prefservice:after-app-defaults");
     os.removeObserver(this, "final-ui-startup");
     os.removeObserver(this, "sessionstore-windows-restored");
     os.removeObserver(this, "browser:purge-session-history");
     os.removeObserver(this, "quit-application-requested");
     os.removeObserver(this, "quit-application-granted");
     os.removeObserver(this, "restart-in-safe-mode");
-#ifdef OBSERVE_LASTWINDOW_CLOSE_TOPICS
-    os.removeObserver(this, "browser-lastwindow-close-requested");
-    os.removeObserver(this, "browser-lastwindow-close-granted");
-#endif
+    if (OBSERVE_LASTWINDOW_CLOSE_TOPICS) {
+      os.removeObserver(this, "browser-lastwindow-close-requested");
+      os.removeObserver(this, "browser-lastwindow-close-granted");
+    }
     os.removeObserver(this, "weave:service:ready");
     os.removeObserver(this, "weave:engine:clients:display-uri");
     os.removeObserver(this, "session-save");
     if (this._bookmarksBackupIdleTime) {
       this._idleService.removeIdleObserver(this, this._bookmarksBackupIdleTime);
       delete this._bookmarksBackupIdleTime;
     }
     if (this._isPlacesInitObserver)
       os.removeObserver(this, "places-init-complete");
     if (this._isPlacesLockedObserver)
       os.removeObserver(this, "places-database-locked");
     if (this._isPlacesShutdownObserver)
       os.removeObserver(this, "places-shutdown");
     os.removeObserver(this, "handle-xul-text-link");
     os.removeObserver(this, "profile-before-change");
-#ifdef MOZ_SERVICES_HEALTHREPORT
-    os.removeObserver(this, "keyword-search");
-#endif
+    if (AppConstants.MOZ_SERVICES_HEALTHREPORT) {
+      os.removeObserver(this, "keyword-search");
+    }
     os.removeObserver(this, "browser-search-engine-modified");
     os.removeObserver(this, "flash-plugin-hang");
     os.removeObserver(this, "xpi-signature-changed");
     os.removeObserver(this, "autocomplete-did-enter-text");
   },
 
   _onAppDefaults: function BG__onAppDefaults() {
     // apply distribution customizations (prefs)
@@ -743,21 +742,21 @@ BrowserGlue.prototype = {
     // prefs are applied in _onAppDefaults()
     this._distributionCustomizer.applyCustomizations();
 
     // handle any UI migration
     this._migrateUI();
 
     WebappManager.init();
     PageThumbs.init();
-#ifdef NIGHTLY_BUILD
-    if (Services.prefs.getBoolPref("dom.identity.enabled")) {
-      SignInToWebsiteUX.init();
+    if (AppConstants.NIGHTLY_BUILD) {
+      if (Services.prefs.getBoolPref("dom.identity.enabled")) {
+        SignInToWebsiteUX.init();
+      }
     }
-#endif
     webrtcUI.init();
     AboutHome.init();
 
     DirectoryLinksProvider.init();
     NewTabUtils.init();
     NewTabUtils.links.addProvider(DirectoryLinksProvider);
     AboutNewTab.init();
 
@@ -773,39 +772,39 @@ BrowserGlue.prototype = {
     Feeds.init();
     ContentPrefServiceParent.init();
 
     LoginManagerParent.init();
     ReaderParent.init();
 
     SelfSupportBackend.init();
 
-#ifndef RELEASE_BUILD
-    let themeName = gBrowserBundle.GetStringFromName("deveditionTheme.name");
-    let vendorShortName = gBrandBundle.GetStringFromName("vendorShortName");
-
-    LightweightThemeManager.addBuiltInTheme({
-      id: "firefox-devedition@mozilla.org",
-      name: themeName,
-      headerURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.header.png",
-      iconURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.icon.png",
-      author: vendorShortName,
-    });
-#endif
+    if (!AppConstants.RELEASE_BUILD) {
+      let themeName = gBrowserBundle.GetStringFromName("deveditionTheme.name");
+      let vendorShortName = gBrandBundle.GetStringFromName("vendorShortName");
+
+      LightweightThemeManager.addBuiltInTheme({
+        id: "firefox-devedition@mozilla.org",
+        name: themeName,
+        headerURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.header.png",
+        iconURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.icon.png",
+        author: vendorShortName,
+      });
+    }
 
     TabCrashHandler.init();
-#ifdef MOZ_CRASHREPORTER
-    PluginCrashReporter.init();
-#endif
+    if (AppConstants.MOZ_CRASHREPORTER) {
+      PluginCrashReporter.init();
+    }
 
     Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
 
-#ifdef NIGHTLY_BUILD
-    AddonWatcher.init(this._notifySlowAddon);
-#endif
+    if (AppConstants.NIGHTLY_BUILD) {
+      AddonWatcher.init(this._notifySlowAddon);
+    }
   },
 
   _checkForOldBuildUpdates: function () {
     // check for update if our build is old
     if (AppConstants.MOZ_UPDATER &&
         Services.prefs.getBoolPref("app.update.enabled") &&
         Services.prefs.getBoolPref("app.update.checkInstallTime")) {
 
@@ -964,25 +963,28 @@ BrowserGlue.prototype = {
     ];
 
     let nb = win.document.getElementById("high-priority-global-notificationbox");
     nb.appendNotification(message, "unsigned-addons-disabled", "",
                           nb.PRIORITY_WARNING_MEDIUM, buttons);
   },
 
   _firstWindowTelemetry: function(aWindow) {
-#ifdef XP_WIN
-    let SCALING_PROBE_NAME = "DISPLAY_SCALING_MSWIN";
-#elifdef XP_MACOSX
-    let SCALING_PROBE_NAME = "DISPLAY_SCALING_OSX";
-#elifdef XP_LINUX
-    let SCALING_PROBE_NAME = "DISPLAY_SCALING_LINUX";
-#else
     let SCALING_PROBE_NAME = "";
-#endif
+    switch (AppConstants.platform) {
+      case "win":
+        SCALING_PROBE_NAME = "DISPLAY_SCALING_MSWIN";
+        break;
+      case "macosx":
+        SCALING_PROBE_NAME = "DISPLAY_SCALING_OSX";
+        break;
+      case "linux":
+        SCALING_PROBE_NAME = "DISPLAY_SCALING_LINUX";
+        break;
+    }
     if (SCALING_PROBE_NAME) {
       let scaling = aWindow.devicePixelRatio * 100;
       Services.telemetry.getHistogramById(SCALING_PROBE_NAME).add(scaling);
     }
   },
 
   // the first browser window has finished initializing
   _onFirstWindowLoaded: function BG__onFirstWindowLoaded(aWindow) {
@@ -995,33 +997,33 @@ BrowserGlue.prototype = {
     // shim for privileged api access.
     PdfJs.init(true);
     // child only: similar to the call above for parent - register content
     // handler and init message manager child shim for privileged api access.
     // With older versions of the extension installed, this load will fail
     // passively.
     Services.ppmm.loadProcessScript("resource://pdf.js/pdfjschildbootstrap.js", true);
 
-#ifdef NIGHTLY_BUILD
-    // Registering Shumway bootstrap script the child processes.
-    Services.ppmm.loadProcessScript("chrome://shumway/content/bootstrap-content.js", true);
-    // Initializing Shumway (shall be run after child script registration).
-    ShumwayUtils.init();
-#endif
-
-#ifdef XP_WIN
-    // For windows seven, initialize the jump list module.
-    const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
-    if (WINTASKBAR_CONTRACTID in Cc &&
-        Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar).available) {
-      let temp = {};
-      Cu.import("resource:///modules/WindowsJumpLists.jsm", temp);
-      temp.WinTaskbarJumpList.startup();
+    if (AppConstants.NIGHTLY_BUILD) {
+      // Registering Shumway bootstrap script the child processes.
+      Services.ppmm.loadProcessScript("chrome://shumway/content/bootstrap-content.js", true);
+      // Initializing Shumway (shall be run after child script registration).
+      ShumwayUtils.init();
     }
-#endif
+
+    if (AppConstants.platform == "win") {
+      // For Windows 7, initialize the jump list module.
+      const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
+      if (WINTASKBAR_CONTRACTID in Cc &&
+          Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar).available) {
+        let temp = {};
+        Cu.import("resource:///modules/WindowsJumpLists.jsm", temp);
+        temp.WinTaskbarJumpList.startup();
+      }
+    }
 
     ProcessHangMonitor.init();
 
     // A channel for "remote troubleshooting" code...
     let channel = new WebChannel("remote-troubleshooting", "remote-troubleshooting");
     channel.listen((id, data, target) => {
       if (data.command == "request") {
         let {Troubleshoot} = Cu.import("resource://gre/modules/Troubleshoot.jsm", {});
@@ -1075,26 +1077,26 @@ BrowserGlue.prototype = {
 
     SelfSupportBackend.uninit();
 
     CustomizationTabPreloader.uninit();
     WebappManager.uninit();
 
     NewTabPrefsProvider.prefs.uninit();
     AboutNewTab.uninit();
-#ifdef NIGHTLY_BUILD
-    if (Services.prefs.getBoolPref("dom.identity.enabled")) {
-      SignInToWebsiteUX.uninit();
+    if (AppConstants.NIGHTLY_BUILD) {
+      if (Services.prefs.getBoolPref("dom.identity.enabled")) {
+        SignInToWebsiteUX.uninit();
+      }
     }
-#endif
     webrtcUI.uninit();
     FormValidationHandler.uninit();
-#ifdef NIGHTLY_BUILD
-    AddonWatcher.uninit();
-#endif
+    if (AppConstants.NIGHTLY_BUILD) {
+      AddonWatcher.uninit();
+    }
   },
 
   _initServiceDiscovery: function () {
     if (!Services.prefs.getBoolPref("browser.casting.enabled")) {
       return;
     }
     var rokuDevice = {
       id: "roku:ecp",
@@ -1111,19 +1113,19 @@ BrowserGlue.prototype = {
     SimpleServiceDiscovery.registerDevice(rokuDevice);
 
     // Search for devices continuously every 120 seconds
     SimpleServiceDiscovery.search(120 * 1000);
   },
 
   // All initial windows have opened.
   _onWindowsRestored: function BG__onWindowsRestored() {
-#ifdef MOZ_DEV_EDITION
-    this._createExtraDefaultProfile();
-#endif
+    if (AppConstants.MOZ_DEV_EDITION) {
+      this._createExtraDefaultProfile();
+    }
 
     this._initServiceDiscovery();
 
     // Show update notification, if needed.
     if (Services.prefs.prefHasUserValue("app.update.postupdate"))
       this._showUpdateNotification();
 
     // Load the "more info" page for a locked places.sqlite
@@ -1148,21 +1150,22 @@ BrowserGlue.prototype = {
           if (!aAddon.userDisabled || !(aAddon.permissions & AddonManager.PERM_CAN_ENABLE))
             return;
 
           win.openUILinkIn("about:newaddon?id=" + aAddon.id, "tab");
         })
       });
     }
 
-#ifdef MOZ_REQUIRE_SIGNING
-    let signingRequired = true;
-#else
-    let signingRequired = Services.prefs.getBoolPref("xpinstall.signatures.required");
-#endif
+    let signingRequired;
+    if (AppConstants.MOZ_REQUIRE_SIGNING) {
+      signingRequired = true;
+    } else {
+      signingRequired = Services.prefs.getBoolPref("xpinstall.signatures.required");
+    }
 
     if (signingRequired) {
       let disabledAddons = AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_DISABLED);
       AddonManager.getAddonsByIDs(disabledAddons, (addons) => {
         for (let addon of addons) {
           if (addon.type == "experiment")
             continue;
 
@@ -1171,29 +1174,26 @@ BrowserGlue.prototype = {
             break;
           }
         }
       });
     }
 
     // Perform default browser checking.
     if (ShellService) {
-#ifdef DEBUG
-      let shouldCheck = false;
-#else
-      let shouldCheck = ShellService.shouldCheckDefaultBrowser;
-#endif
-#ifndef RELEASE_BUILD
-      let promptCount =
-        Services.prefs.getIntPref("browser.shell.defaultBrowserCheckCount");
-      let skipDefaultBrowserCheck =
-        Services.prefs.getBoolPref("browser.shell.skipDefaultBrowserCheck");
-#else
+      let shouldCheck = AppConstants.DEBUG ? false :
+                                             ShellService.shouldCheckDefaultBrowser;
+      let promptCount;
       let skipDefaultBrowserCheck = false;
-#endif
+      if (!AppConstants.RELEASE_BUILD) {
+        promptCount =
+          Services.prefs.getIntPref("browser.shell.defaultBrowserCheckCount");
+        skipDefaultBrowserCheck =
+          Services.prefs.getBoolPref("browser.shell.skipDefaultBrowserCheck");
+      }
       let willRecoverSession = false;
       try {
         let ss = Cc["@mozilla.org/browser/sessionstartup;1"].
                  getService(Ci.nsISessionStartup);
         willRecoverSession =
           (ss.sessionType == Ci.nsISessionStartup.RECOVER_SESSION);
       }
       catch (ex) { /* never mind; suppose SessionStore is broken */ }
@@ -1223,22 +1223,22 @@ BrowserGlue.prototype = {
         } else {
           promptCount++;
         }
         if (promptCount > 3) {
           willPrompt = false;
         }
       }
 
-#ifndef RELEASE_BUILD
-      if (willPrompt) {
-        Services.prefs.setIntPref("browser.shell.defaultBrowserCheckCount",
-                                  promptCount);
+      if (!AppConstants.RELEASE_BUILD) {
+        if (willPrompt) {
+          Services.prefs.setIntPref("browser.shell.defaultBrowserCheckCount",
+                                    promptCount);
+        }
       }
-#endif
 
       try {
         // Report default browser status on startup to telemetry
         // so we can track whether we are the default.
         Services.telemetry.getHistogramById("BROWSER_IS_USER_DEFAULT")
                           .add(isDefault);
         Services.telemetry.getHistogramById("BROWSER_IS_USER_DEFAULT_ERROR")
                           .add(isDefaultError);
@@ -1261,18 +1261,20 @@ BrowserGlue.prototype = {
     }
     if (AppConstants.platform == "win") {
       // Handles prompting to inform about incompatibilites when accessibility
       // and e10s are active together.
       E10SAccessibilityCheck.init();
     }
   },
 
-#ifdef MOZ_DEV_EDITION
   _createExtraDefaultProfile: function () {
+    if (!AppConstants.MOZ_DEV_EDITION) {
+      return;
+    }
     // If Developer Edition is the only installed Firefox version and no other
     // profiles are present, create a second one for use by other versions.
     // This helps Firefox versions earlier than 35 avoid accidentally using the
     // unsuitable Developer Edition profile.
     let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
                          .getService(Ci.nsIToolkitProfileService);
     let profileCount = profileService.profileCount;
     if (profileCount == 1 && profileService.selectedProfile.name != "default") {
@@ -1292,17 +1294,16 @@ BrowserGlue.prototype = {
         OS.File.removeDir(newProfilePath).then(() => {
           return OS.File.makeDir(newProfilePath);
         }).then(null, e => {
           Cu.reportError("Could not empty profile 'default': " + e);
         });
       }
     }
   },
-#endif
 
   _maybeMigrateTabGroups() {
     let migrationObserver = (stateAsSupportsString, topic) => {
       Services.obs.removeObserver(migrationObserver, "sessionstore-state-read");
       TabGroupsMigrator.migrate(stateAsSupportsString);
     };
     Services.obs.addObserver(migrationObserver, "sessionstore-state-read", false);
   },
@@ -1759,17 +1760,17 @@ BrowserGlue.prototype = {
       delete this._bookmarksBackupIdleTime;
     }
   },
 
   /**
    * If a backup for today doesn't exist, this creates one.
    */
   _backupBookmarks: function BG__backupBookmarks() {
-    return Task.spawn(function() {
+    return Task.spawn(function*() {
       let lastBackupFile = yield PlacesBackups.getMostRecentBackup();
       // Should backup bookmarks if there are no backups or the maximum
       // interval between backups elapsed.
       if (!lastBackupFile ||
           new Date() - PlacesBackups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS * 86400000) {
         let maxBackups = Services.prefs.getIntPref("browser.bookmarks.max_backups");
         yield PlacesBackups.create(maxBackups);
       }
@@ -1897,30 +1898,30 @@ BrowserGlue.prototype = {
         } else {
           currentset = currentset.replace(/(^|,)window-controls($|,)/,
                                           "$1downloads-button,window-controls$2")
         }
         xulStore.setValue(BROWSER_DOCURL, "nav-bar", "currentset", currentset);
       }
     }
 
-#ifdef XP_WIN
-    if (currentUIVersion < 10) {
-      // For Windows systems with display set to > 96dpi (i.e. systemDefaultScale
-      // will return a value > 1.0), we want to discard any saved full-zoom settings,
-      // as we'll now be scaling the content according to the system resolution
-      // scale factor (Windows "logical DPI" setting)
-      let sm = Cc["@mozilla.org/gfx/screenmanager;1"].getService(Ci.nsIScreenManager);
-      if (sm.systemDefaultScale > 1.0) {
-        let cps2 = Cc["@mozilla.org/content-pref/service;1"].
-                   getService(Ci.nsIContentPrefService2);
-        cps2.removeByName("browser.content.full-zoom", null);
+    if (AppConstants.platform == "win") {
+      if (currentUIVersion < 10) {
+        // For Windows systems with display set to > 96dpi (i.e. systemDefaultScale
+        // will return a value > 1.0), we want to discard any saved full-zoom settings,
+        // as we'll now be scaling the content according to the system resolution
+        // scale factor (Windows "logical DPI" setting)
+        let sm = Cc["@mozilla.org/gfx/screenmanager;1"].getService(Ci.nsIScreenManager);
+        if (sm.systemDefaultScale > 1.0) {
+          let cps2 = Cc["@mozilla.org/content-pref/service;1"].
+                     getService(Ci.nsIContentPrefService2);
+          cps2.removeByName("browser.content.full-zoom", null);
+        }
       }
     }
-#endif
 
     if (currentUIVersion < 11) {
       Services.prefs.clearUserPref("dom.disable_window_move_resize");
       Services.prefs.clearUserPref("dom.disable_window_flip");
       Services.prefs.clearUserPref("dom.event.contextmenu.enabled");
       Services.prefs.clearUserPref("javascript.enabled");
       Services.prefs.clearUserPref("permissions.default.image");
     }
@@ -2536,17 +2537,17 @@ ContentPermissionPrompt.prototype = {
     var mainAction = popupNotificationActions.length ?
                        popupNotificationActions[0] : null;
     var secondaryActions = popupNotificationActions.splice(1);
 
     // Only allow exactly one permission request here.
     let types = aRequest.types.QueryInterface(Ci.nsIArray);
     if (types.length != 1) {
       aRequest.cancel();
-      return;
+      return undefined;
     }
 
     if (!aOptions)
       aOptions = {};
     aOptions.displayURI = requestPrincipal.URI;
 
     return chromeWin.PopupNotifications.show(browser, aNotificationId, aMessage, aAnchorId,
                                              mainAction, secondaryActions, aOptions);
@@ -2778,26 +2779,26 @@ var DefaultBrowserCheck = {
     if (this._notification) {
       this._notification.close();
     }
   },
 
   setAsDefault: function() {
     let claimAllTypes = true;
     let setAsDefaultError = false;
-#ifdef XP_WIN
-    try {
-      // In Windows 8+, the UI for selecting default protocol is much
-      // nicer than the UI for setting file type associations. So we
-      // only show the protocol association screen on Windows 8+.
-      // Windows 8 is version 6.2.
-      let version = Services.sysinfo.getProperty("version");
-      claimAllTypes = (parseFloat(version) < 6.2);
-    } catch (ex) { }
-#endif
+    if (AppConstants.platform == "win") {
+      try {
+        // In Windows 8+, the UI for selecting default protocol is much
+        // nicer than the UI for setting file type associations. So we
+        // only show the protocol association screen on Windows 8+.
+        // Windows 8 is version 6.2.
+        let version = Services.sysinfo.getProperty("version");
+        claimAllTypes = (parseFloat(version) < 6.2);
+      } catch (ex) { }
+    }
     try {
       ShellService.setDefaultBrowser(claimAllTypes, false);
 
       if (this._setAsDefaultTimer) {
         this._setAsDefaultTimer.cancel();
       }
 
       this._setAsDefaultButtonClickStartTime = Math.floor(Date.now() / 1000);
@@ -2960,17 +2961,16 @@ var DefaultBrowserCheck = {
       let popup = doc.getElementById(this.OPTIONPOPUP);
       popup.removeEventListener("command", this);
       popup.remove();
       delete this._notification;
     }
   },
 };
 
-#ifdef E10S_TESTING_ONLY
 var E10SUINotification = {
   CURRENT_PROMPT_PREF: "browser.displayedE10SPrompt.1",
   PREVIOUS_PROMPT_PREF: "browser.displayedE10SPrompt",
 
   get forcedOn() {
     try {
       return Services.prefs.getBoolPref("browser.tabs.remote.force-enable");
     } catch (e) {}
@@ -3025,23 +3025,23 @@ var E10SUINotification = {
 
       let e10sPromptShownCount = 0;
       try {
         e10sPromptShownCount = Services.prefs.getIntPref(this.CURRENT_PROMPT_PREF);
       } catch(e) {}
 
       let isHardwareAccelerated = true;
       // Linux and Windows are currently ok, mac not so much.
-#ifdef XP_MACOSX
-      try {
-        let win = RecentWindow.getMostRecentBrowserWindow();
-        let winutils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-        isHardwareAccelerated = winutils.layerManagerType != "Basic";
-      } catch (e) {}
-#endif
+      if (AppConstants.platform == "macosx") {
+        try {
+          let win = RecentWindow.getMostRecentBrowserWindow();
+          let winutils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+          isHardwareAccelerated = winutils.layerManagerType != "Basic";
+        } catch (e) {}
+      }
 
       if (!Services.appinfo.inSafeMode &&
           !Services.appinfo.accessibilityEnabled &&
           isHardwareAccelerated &&
           e10sPromptShownCount < 5) {
         Services.tm.mainThread.dispatch(() => {
           try {
             this._showE10SPrompt();
@@ -3108,17 +3108,16 @@ var E10SUINotification = {
                                              .querySelector("popupnotificationcontent");
     for (let highlight of highlights) {
       let highlightLabel = win.document.createElement("label");
       highlightLabel.setAttribute("value", highlight);
       doorhangerExtraContent.appendChild(highlightLabel);
     }
   }
 };
-#endif // E10S_TESTING_ONLY
 
 var E10SAccessibilityCheck = {
   init: function() {
     Services.obs.addObserver(this, "a11y-init-or-shutdown", true);
     Services.obs.addObserver(this, "quit-application-granted", true);
   },
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
--- a/build.gradle
+++ b/build.gradle
@@ -20,20 +20,16 @@ buildscript {
         jcenter()
 
         // For spoon-gradle-plugin SNAPSHOT release.  This needs to go before
         // the snapshots repository, otherwise we find a remote 1.0.3-SNAPSHOT
         // that doesn't include nalexander's local changes.
         maven {
             url "file://${gradle.mozconfig.topsrcdir}/mobile/android/gradle/m2repo"
         }
-        // For spoon SNAPSHOT releases.
-        maven {
-            url 'https://oss.sonatype.org/content/repositories/snapshots'
-        }
     }
 
     dependencies {
         // Unit testing support was added in 1.1.0. IntelliJ 14.1.4 and Android
         // Studio 1.2.1.1 appear to work fine with plugin version 1.3.0.
         classpath 'com.android.tools.build:gradle:1.3.0'
         classpath('com.stanfy.spoon:spoon-gradle-plugin:1.0.3-SNAPSHOT') {
             // Without these, we get errors linting.
--- a/devtools/client/debugger/debugger-controller.js
+++ b/devtools/client/debugger/debugger-controller.js
@@ -1163,17 +1163,17 @@ StackFrames.prototype = {
       this._syncedWatchExpressions =
       this._currentWatchExpressions = "[" +
         sanitizedExpressions.map(aString =>
           "eval(\"" +
             "try {" +
               // Make sure all quotes are escaped in the expression's syntax,
               // and add a newline after the statement to avoid comments
               // breaking the code integrity inside the eval block.
-              aString.replace(/"/g, "\\$&") + "\" + " + "'\\n'" + " + \"" +
+              aString.replace(/\\/g, "\\\\").replace(/"/g, "\\$&") + "\" + " + "'\\n'" + " + \"" +
             "} catch (e) {" +
               "e.name + ': ' + e.message;" + // TODO: Bug 812765, 812764.
             "}" +
           "\")"
         ).join(",") +
       "]";
     }
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_watch-expressions-02.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_watch-expressions-02.js
@@ -29,16 +29,19 @@ function test() {
       .then(finishTest)
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
   });
 
   function addExpressions() {
+    // https://bugzilla.mozilla.org/show_bug.cgi?id=1205353
+    // BZ#1205353 - wrong result for string replace with backslash-dollar.
+    gWatch.addExpression("'$$$'.replace(/\\$/, 'foo')");
     gWatch.addExpression("'a'");
     gWatch.addExpression("\"a\"");
     gWatch.addExpression("'a\"\"'");
     gWatch.addExpression("\"a''\"");
     gWatch.addExpression("?");
     gWatch.addExpression("a");
     gWatch.addExpression("this");
     gWatch.addExpression("this.canada");
@@ -56,25 +59,26 @@ function test() {
     gWatch.addExpression("{}.foo");
     gWatch.addExpression("{}.foo()");
     gWatch.addExpression("({}).foo()");
     gWatch.addExpression("new Array(-1)");
     gWatch.addExpression("4.2.toExponential(-4.2)");
     gWatch.addExpression("throw new Error(\"bazinga\")");
     gWatch.addExpression("({ get error() { throw new Error(\"bazinga\") } }).error");
     gWatch.addExpression("throw { get name() { throw \"bazinga\" } }");
+
   }
 
   function performTest() {
     let deferred = promise.defer();
 
     is(gDebugger.document.querySelectorAll(".dbg-expression[hidden=true]").length, 0,
       "There should be 0 hidden nodes in the watch expressions container");
-    is(gDebugger.document.querySelectorAll(".dbg-expression:not([hidden=true])").length, 27,
-      "There should be 27 visible nodes in the watch expressions container");
+    is(gDebugger.document.querySelectorAll(".dbg-expression:not([hidden=true])").length, 28,
+      "There should be 28 visible nodes in the watch expressions container");
 
     test1(function() {
       test2(function() {
         test3(function() {
           test4(function() {
             test5(function() {
               test6(function() {
                 test7(function() {
@@ -92,129 +96,129 @@ function test() {
     });
 
     return deferred.promise;
   }
 
   function finishTest() {
     is(gDebugger.document.querySelectorAll(".dbg-expression[hidden=true]").length, 0,
       "There should be 0 hidden nodes in the watch expressions container");
-    is(gDebugger.document.querySelectorAll(".dbg-expression:not([hidden=true])").length, 27,
-      "There should be 27 visible nodes in the watch expressions container");
+    is(gDebugger.document.querySelectorAll(".dbg-expression:not([hidden=true])").length, 28,
+      "There should be 28 visible nodes in the watch expressions container");
   }
 
   function test1(aCallback) {
     gDebugger.once(gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS, () => {
-      checkWatchExpressions(26, {
+      checkWatchExpressions(27, {
         a: "ReferenceError: a is not defined",
         this: { type: "object", class: "Object" },
         prop: { type: "object", class: "String" },
         args: { type: "undefined" }
       });
       aCallback();
     });
 
     callInTab(gTab, "test");
   }
 
   function test2(aCallback) {
     gDebugger.once(gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS, () => {
-      checkWatchExpressions(26, {
+      checkWatchExpressions(27, {
         a: { type: "undefined" },
         this: { type: "object", class: "Window" },
         prop: { type: "undefined" },
         args: "sensational"
       });
       aCallback();
     });
 
     EventUtils.sendMouseEvent({ type: "mousedown" },
       gDebugger.document.getElementById("resume"),
       gDebugger);
   }
 
   function test3(aCallback) {
     gDebugger.once(gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS, () => {
-      checkWatchExpressions(26, {
+      checkWatchExpressions(27, {
         a: { type: "object", class: "Object" },
         this: { type: "object", class: "Window" },
         prop: { type: "undefined" },
         args: "sensational"
       });
       aCallback();
     });
 
     EventUtils.sendMouseEvent({ type: "mousedown" },
       gDebugger.document.getElementById("resume"),
       gDebugger);
   }
 
   function test4(aCallback) {
     gDebugger.once(gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS, () => {
-      checkWatchExpressions(27, {
+      checkWatchExpressions(28, {
         a: 5,
         this: { type: "object", class: "Window" },
         prop: { type: "undefined" },
         args: "sensational"
       });
       aCallback();
     });
 
     gWatch.addExpression("a = 5");
     EventUtils.sendKey("RETURN", gDebugger);
   }
 
   function test5(aCallback) {
     gDebugger.once(gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS, () => {
-      checkWatchExpressions(27, {
+      checkWatchExpressions(28, {
         a: 5,
         this: { type: "object", class: "Window" },
         prop: { type: "undefined" },
         args: "sensational"
       });
       aCallback();
     });
 
     gWatch.addExpression("encodeURI(\"\\\")");
     EventUtils.sendKey("RETURN", gDebugger);
   }
 
   function test6(aCallback) {
     gDebugger.once(gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS, () => {
-      checkWatchExpressions(27, {
+      checkWatchExpressions(28, {
         a: 5,
         this: { type: "object", class: "Window" },
         prop: { type: "undefined" },
         args: "sensational"
       });
       aCallback();
     })
 
     gWatch.addExpression("decodeURI(\"\\\")");
     EventUtils.sendKey("RETURN", gDebugger);
   }
 
   function test7(aCallback) {
     gDebugger.once(gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS, () => {
-      checkWatchExpressions(27, {
+      checkWatchExpressions(28, {
         a: 5,
         this: { type: "object", class: "Window" },
         prop: { type: "undefined" },
         args: "sensational"
       });
       aCallback();
     });
 
     gWatch.addExpression("?");
     EventUtils.sendKey("RETURN", gDebugger);
   }
 
   function test8(aCallback) {
     gDebugger.once(gDebugger.EVENTS.FETCHED_WATCH_EXPRESSIONS, () => {
-      checkWatchExpressions(27, {
+      checkWatchExpressions(28, {
         a: 5,
         this: { type: "object", class: "Window" },
         prop: { type: "undefined" },
         args: "sensational"
       });
       aCallback();
     });
 
@@ -273,16 +277,17 @@ function test() {
     let w20 = scope.get("{}.foo");
     let w21 = scope.get("{}.foo()");
     let w22 = scope.get("({}).foo()");
     let w23 = scope.get("new Array(-1)");
     let w24 = scope.get("4.2.toExponential(-4.2)");
     let w25 = scope.get("throw new Error(\"bazinga\")");
     let w26 = scope.get("({ get error() { throw new Error(\"bazinga\") } }).error");
     let w27 = scope.get("throw { get name() { throw \"bazinga\" } }");
+    let w28 = scope.get("'$$$'.replace(/\\$/, 'foo')");
 
     ok(w1, "The first watch expression should be present in the scope.");
     ok(w2, "The second watch expression should be present in the scope.");
     ok(w3, "The third watch expression should be present in the scope.");
     ok(w4, "The fourth watch expression should be present in the scope.");
     ok(w5, "The fifth watch expression should be present in the scope.");
     ok(w6, "The sixth watch expression should be present in the scope.");
     ok(w7, "The seventh watch expression should be present in the scope.");
@@ -301,16 +306,17 @@ function test() {
     ok(w20, "The 20th watch expression should be present in the scope.");
     ok(w21, "The 21st watch expression should be present in the scope.");
     ok(w22, "The 22nd watch expression should be present in the scope.");
     ok(w23, "The 23nd watch expression should be present in the scope.");
     ok(w24, "The 24th watch expression should be present in the scope.");
     ok(w25, "The 25th watch expression should be present in the scope.");
     ok(w26, "The 26th watch expression should be present in the scope.");
     ok(!w27, "The 27th watch expression should not be present in the scope.");
+    ok(w28, "The 28th watch expression should be present in the scope.");
 
     is(w1.value, "a", "The first value is correct.");
     is(w2.value, "a", "The second value is correct.");
     is(w3.value, "a\"\"", "The third value is correct.");
     is(w4.value, "a''", "The fourth value is correct.");
     is(w5.value, "SyntaxError: expected expression, got '?'", "The fifth value is correct.");
 
     if (typeof expected_a == "object") {
@@ -362,10 +368,11 @@ function test() {
 
     is(w20.value, "SyntaxError: expected expression, got '.'", "The 20th value is correct.");
     is(w21.value, "SyntaxError: expected expression, got '.'", "The 21th value is correct.");
     is(w22.value, "TypeError: (intermediate value).foo is not a function", "The 22th value is correct.");
     is(w23.value, "RangeError: invalid array length", "The 23th value is correct.");
     is(w24.value, "RangeError: precision -4 out of range", "The 24th value is correct.");
     is(w25.value, "Error: bazinga", "The 25th value is correct.");
     is(w26.value, "Error: bazinga", "The 26th value is correct.");
+    is(w28.value, 'foo$$', "The 28th value is correct.");
   }
 }
--- a/docshell/test/chrome/test_bug565388.xul
+++ b/docshell/test/chrome/test_bug565388.xul
@@ -50,26 +50,28 @@ https://bugzilla.mozilla.org/show_bug.cg
           iid.equals(Components.interfaces.nsISupportsWeakReference))
         return this;
       throw Components.results.NS_ERROR_NO_INTERFACE;
     }
   }
 
   var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].
   createInstance(Ci.nsIPrincipal);
-  var docShell = Cc["@mozilla.org/appshell/appShellService;1"].
+  var webNav = Cc["@mozilla.org/appshell/appShellService;1"].
   getService(Ci.nsIAppShellService).
-  createWindowlessBrowser(true).
+  createWindowlessBrowser(true);
+  var docShell = webNav.
   QueryInterface(Ci.nsIInterfaceRequestor).
   getInterface(Ci.nsIDocShell);
   docShell.createAboutBlankContentViewer(systemPrincipal);
   var win = docShell.contentViewer.DOMDocument.defaultView;
 
   progressListener.add(docShell, function(){
     is(win.document.documentURI, "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window/>");
+    webNav.close();
     SimpleTest.finish();
   });
 
   win.location = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window/>";
 
   ]]>
   </script>
 
--- a/dom/bluetooth/common/webapi/BluetoothManager.cpp
+++ b/dom/bluetooth/common/webapi/BluetoothManager.cpp
@@ -8,16 +8,17 @@
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
 #include "BluetoothUtils.h"
 
 #include "mozilla/dom/bluetooth/BluetoothAdapter.h"
 #include "mozilla/dom/bluetooth/BluetoothManager.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/BluetoothManagerBinding.h"
+#include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsIPermissionManager.h"
 #include "nsThreadUtils.h"
 
 using namespace mozilla;
 
@@ -279,8 +280,15 @@ BluetoothManager::Notify(const Bluetooth
   }
 }
 
 JSObject*
 BluetoothManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return BluetoothManagerBinding::Wrap(aCx, this, aGivenProto);
 }
+
+// static
+bool
+BluetoothManager::B2GGattClientEnabled(JSContext* cx, JSObject* aGlobal)
+{
+  return !Preferences::GetBool("dom.bluetooth.webbluetooth.enabled");
+}
--- a/dom/bluetooth/common/webapi/BluetoothManager.h
+++ b/dom/bluetooth/common/webapi/BluetoothManager.h
@@ -72,16 +72,22 @@ public:
   /**
    * Create a BluetoothAdapter object based on properties array
    * and append it into adapters array.
    *
    * @param aValue [in] Properties array to create BluetoothAdapter object
    */
   void AppendAdapter(const BluetoothValue& aValue);
 
+  /**
+   * Check whether B2G only GATT client API is enabled (true) or W3C
+   * WebBluetooth API is enabled (false).
+   */
+  static bool B2GGattClientEnabled(JSContext* cx, JSObject* aGlobal);
+
 private:
   BluetoothManager(nsPIDOMWindow* aWindow);
   ~BluetoothManager();
 
   /**
    * Check whether default adapter exists.
    */
   bool DefaultAdapterExists()
--- a/dom/webidl/BluetoothAdapter.webidl
+++ b/dom/webidl/BluetoothAdapter.webidl
@@ -123,20 +123,27 @@ interface BluetoothAdapter : EventTarget
 
   [NewObject]
   Promise<void> pair(DOMString deviceAddress);
   [NewObject]
   Promise<void> unpair(DOMString deviceAddress);
 
   sequence<BluetoothDevice> getPairedDevices();
 
-  [NewObject]
+  /**
+   * [B2G only GATT client API]
+   * |startLeScan| and |stopLeScan| methods are exposed only if
+   * "dom.bluetooth.webbluetooth.enabled" preference is false.
+   */
+  [NewObject,
+   Func="mozilla::dom::bluetooth::BluetoothManager::B2GGattClientEnabled"]
   Promise<BluetoothDiscoveryHandle> startLeScan(sequence<DOMString> serviceUuids);
 
-  [NewObject]
+  [NewObject,
+   Func="mozilla::dom::bluetooth::BluetoothManager::B2GGattClientEnabled"]
   Promise<void> stopLeScan(BluetoothDiscoveryHandle discoveryHandle);
 
   [NewObject, Throws, AvailableIn=CertifiedApps]
   DOMRequest getConnectedDevices(unsigned short serviceUuid);
 
   /**
    * Connect/Disconnect to a specific service of a target remote device.
    * To check the value of service UUIDs, please check "Bluetooth Assigned
--- a/dom/webidl/BluetoothDevice.webidl
+++ b/dom/webidl/BluetoothDevice.webidl
@@ -11,17 +11,22 @@ interface BluetoothDevice : EventTarget
   readonly attribute BluetoothClassOfDevice cod;
   readonly attribute DOMString              name;
   readonly attribute boolean                paired;
   readonly attribute BluetoothDeviceType    type;
 
   /**
    * Retrieve the BluetoothGatt interface to interact with remote BLE devices.
    * This attribute is null if the device type is not dual or le.
+   *
+   * [B2G only GATT client API]
+   * gatt attribute is exposed only if "dom.bluetooth.webbluetooth.enabled"
+   * preference is false.
    */
+  [Func="mozilla::dom::bluetooth::BluetoothManager::B2GGattClientEnabled"]
   readonly attribute BluetoothGatt?         gatt;
 
   [Cached, Pure]
   readonly attribute sequence<DOMString>    uuids;
 
   // Fired when attribute(s) of BluetoothDevice changed
            attribute EventHandler           onattributechanged;
 
--- a/dom/webidl/BluetoothGatt.webidl
+++ b/dom/webidl/BluetoothGatt.webidl
@@ -1,15 +1,21 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-[CheckAnyPermissions="bluetooth"]
+/**
+ * [B2G only GATT client API]
+ * BluetoothGatt interface is exposed only if
+ * "dom.bluetooth.webbluetooth.enabled" preference is false.
+ */
+[CheckAnyPermissions="bluetooth",
+ Func="mozilla::dom::bluetooth::BluetoothManager::B2GGattClientEnabled"]
 interface BluetoothGatt : EventTarget
 {
   [Cached, Pure]
   readonly attribute sequence<BluetoothGattService> services;
   readonly attribute BluetoothConnectionState       connectionState;
 
   // Fired when the value of any characteristic changed
            attribute EventHandler                   oncharacteristicchanged;
--- a/dom/webidl/BluetoothGattCharacteristicEvent.webidl
+++ b/dom/webidl/BluetoothGattCharacteristicEvent.webidl
@@ -1,15 +1,21 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+/**
+ * [B2G only GATT client API]
+ * BluetoothGattCharacteristicEvent interface is exposed only if
+ * "dom.bluetooth.webbluetooth.enabled" preference is false.
+ */
 [CheckAnyPermissions="bluetooth",
+ Func="mozilla::dom::bluetooth::BluetoothManager::B2GGattClientEnabled",
  Constructor(DOMString type,
              optional BluetoothGattCharacteristicEventInit eventInitDict)]
 interface BluetoothGattCharacteristicEvent : Event
 {
   readonly attribute BluetoothGattCharacteristic? characteristic;
 };
 
 dictionary BluetoothGattCharacteristicEventInit : EventInit
--- a/dom/webidl/BluetoothLeDeviceEvent.webidl
+++ b/dom/webidl/BluetoothLeDeviceEvent.webidl
@@ -1,15 +1,21 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+/**
+ * [B2G only GATT client API]
+ * BluetoothLeDeviceEvent interface is exposed only if
+ * "dom.bluetooth.webbluetooth.enabled" preference is false.
+ */
 [CheckAnyPermissions="bluetooth",
+ Func="mozilla::dom::bluetooth::BluetoothManager::B2GGattClientEnabled",
  Constructor(DOMString type, optional BluetoothLeDeviceEventInit eventInitDict)]
 interface BluetoothLeDeviceEvent : Event
 {
   readonly attribute BluetoothDevice? device;
   readonly attribute short rssi;
   [Throws]
   readonly attribute ArrayBuffer? scanRecord;
 };
--- a/mobile/android/app/base/build.gradle
+++ b/mobile/android/app/base/build.gradle
@@ -65,16 +65,20 @@ android {
                 srcDir "${topsrcdir}/${mozconfig.substs.MOZ_BRANDING_DIRECTORY}/res"
                 srcDir "${project.buildDir}/generated/source/preprocessed_resources" // See syncPreprocessedResources.
                 srcDir "${topsrcdir}/mobile/android/base/resources"
                 srcDir "${topsrcdir}/mobile/android/services/src/main/res"
                 if (mozconfig.substs.MOZ_CRASHREPORTER) {
                     srcDir "${topsrcdir}/mobile/android/base/crashreporter/res"
                 }
             }
+
+            assets {
+                srcDir "${topsrcdir}/mobile/android/app/assets"
+            }
         }
 
         test {
             java {
                 srcDir "${topsrcdir}/mobile/android/tests/background/junit4/src"
             }
 
             resources {
@@ -117,17 +121,17 @@ dependencies {
         compile 'com.google.android.gms:play-services-base:8.1.0'
         compile 'com.google.android.gms:play-services-gcm:8.1.0'
     }
 
     compile project(':thirdparty')
 
     testCompile 'junit:junit:4.12'
     testCompile 'org.robolectric:robolectric:3.0'
-    testCompile 'org.simpleframework:simple-http:4.1.13'
+    testCompile 'org.simpleframework:simple-http:6.0.1'
     testCompile 'org.mockito:mockito-core:1.10.19'
 }
 
 apply plugin: 'idea'
 
 idea {
     module {
     }
--- a/mobile/android/app/build.gradle
+++ b/mobile/android/app/build.gradle
@@ -7,41 +7,72 @@ android {
     buildToolsVersion "23.0.1"
 
     defaultConfig {
         targetSdkVersion 23
         minSdkVersion 15 
         applicationId mozconfig.substs.ANDROID_PACKAGE_NAME
         testApplicationId 'org.mozilla.roboexample.test'
         testInstrumentationRunner 'org.mozilla.gecko.FennecInstrumentationTestRunner'
+        manifestPlaceholders = [
+            ANDROID_PACKAGE_NAME: mozconfig.substs.ANDROID_PACKAGE_NAME,
+            MOZ_ANDROID_MIN_SDK_VERSION: mozconfig.substs.MOZ_ANDROID_MIN_SDK_VERSION,
+            MOZ_ANDROID_SHARED_ID: "${mozconfig.substs.ANDROID_PACKAGE_NAME}.sharedID",
+        ]
     }
 
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_7
         targetCompatibility JavaVersion.VERSION_1_7
     }
+ 
+    dexOptions {
+        javaMaxHeapSize "2g"
+    }
 
     lintOptions {
         abortOnError false
     }
 
     buildTypes {
         release {
+            shrinkResources true
             minifyEnabled true
             proguardFile "${topsrcdir}/mobile/android/config/proguard/proguard.cfg"
         }
     }
 
+    productFlavors {
+        // For fast local development.  If you have an API 21 device, you should
+        // use this.
+        local {
+            // Setting `minSdkVersion 21` allows the Android gradle plugin to
+            // pre-DEX each module and produce an APK that can be tested on
+            // Android Lollipop without time consuming DEX merging processes.
+            minSdkVersion 21
+            dexOptions {
+                preDexLibraries true
+                multiDexEnabled true
+            }
+        }
+        // For local development on older devices.  Use this only if you only
+        // have a pre-API 21 device, or if you want to test API-specific things.
+        localOld {
+        }
+        // Automation builds.
+        automation {
+        }
+    }
+
     sourceSets {
         main {
             manifest.srcFile "${topobjdir}/mobile/android/base/AndroidManifest.xml"
         }
 
         androidTest {
-            manifest.srcFile "${topobjdir}/mobile/android/tests/browser/robocop/AndroidManifest.xml"
             java {
                 srcDir "${topsrcdir}/mobile/android/tests/browser/robocop/src"
                 srcDir "${topsrcdir}/mobile/android/tests/background/junit3/src"
                 srcDir "${topsrcdir}/mobile/android/tests/browser/junit3/src"
                 srcDir "${topsrcdir}/mobile/android/tests/javaddons/src"
             }
             res {
                 srcDir "${topsrcdir}/mobile/android/tests/browser/robocop/res"
@@ -118,31 +149,35 @@ task buildOmnijar(type:Exec) {
     doLast {
         if (execResult.exitValue != 0) {
             throw new GradleException("Process '${commandLine}' finished with non-zero exit value ${execResult.exitValue}:\n\n${standardOutput.toString()}")
         }
     }
 }
 
 android.applicationVariants.all { variant ->
-    // We only insert omni.ja and the .so libraries into debug builds.
-    def name = variant.buildType.name
-    if (!name.contains(com.android.builder.core.BuilderConstants.DEBUG)) {
+    // Like 'local' or 'localOld'.
+    def productFlavor = variant.productFlavors[0].name
+    // Like 'debug' or 'release'.
+    def buildType = variant.buildType.name
+
+    // We insert omni.ja and the .so libraries into all local builds.
+    if (!productFlavor.startsWith('local')) {
         return
     }
 
     syncOmnijarFromDistDir.dependsOn buildOmnijar
-    def generateAssetsTask = tasks.findByName("generate${name.capitalize()}Assets")
+    def generateAssetsTask = tasks.findByName("generate${productFlavor.capitalize()}${buildType.capitalize()}Assets")
     generateAssetsTask.dependsOn syncOmnijarFromDistDir
     generateAssetsTask.dependsOn syncLibsFromDistDir
     generateAssetsTask.dependsOn syncAssetsFromDistDir
 
-    android.sourceSets.debug.assets.srcDir syncOmnijarFromDistDir.destinationDir
-    android.sourceSets.debug.assets.srcDir syncAssetsFromDistDir.destinationDir
-    android.sourceSets.debug.jniLibs.srcDir syncLibsFromDistDir.destinationDir
+    android.sourceSets."${productFlavor}${buildType.capitalize()}".assets.srcDir syncOmnijarFromDistDir.destinationDir
+    android.sourceSets."${productFlavor}${buildType.capitalize()}".assets.srcDir syncAssetsFromDistDir.destinationDir
+    android.sourceSets."${productFlavor}${buildType.capitalize()}".jniLibs.srcDir syncLibsFromDistDir.destinationDir
 }
 
 apply plugin: 'spoon'
 
 spoon {
     // For now, let's be verbose.
     debug = true
     // It's not helpful to pass when we don't have a device connected.
@@ -161,20 +196,20 @@ spoon {
     }
     if (spoonPackageName) {
         instrumentationArgs = ['-e', "package=${spoonPackageName}".toString()]
     }
 }
 
 // See discussion at https://github.com/stanfy/spoon-gradle-plugin/issues/9.
 afterEvaluate {
-    tasks["spoon${android.testBuildType.capitalize()}AndroidTest"].outputs.upToDateWhen { false }
+    tasks["spoonLocal${android.testBuildType.capitalize()}AndroidTest"].outputs.upToDateWhen { false }
 
     // This is an awkward way to define different sets of instrumentation tests.
     // The task name itself is fished at runtime and the package name configured
     // in the spoon configuration.
     task runBrowserTests {
-        dependsOn tasks["spoonDebugAndroidTest"]
+        dependsOn tasks["spoonLocalDebugAndroidTest"]
     }
     task runBackgroundTests {
-        dependsOn tasks["spoonDebugAndroidTest"]
+        dependsOn tasks["spoonLocalDebugAndroidTest"]
     }
 }
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.mozilla.roboexample.test"
+    android:sharedUserId="${MOZ_ANDROID_SHARED_ID}"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk android:minSdkVersion="${MOZ_ANDROID_MIN_SDK_VERSION}"
+              android:targetSdkVersion="22"/>
+    <!-- TODO: re-instate maxSdkVersion. -->
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+    <instrumentation
+        android:name="org.mozilla.gecko.FennecInstrumentationTestRunner"
+        android:targetPackage="${ANDROID_PACKAGE_NAME}" />
+
+    <application
+        android:label="@string/app_name">
+
+        <uses-library android:name="android.test.runner" />
+
+        <!-- Fake handlers to ensure that we have some share intents to show in our share handler list -->
+        <activity android:name="org.mozilla.gecko.RobocopShare1"
+                  android:label="Robocop fake activity">
+
+            <intent-filter android:label="Fake robocop share handler 1">
+                <action android:name="android.intent.action.SEND" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="text/*" />
+                <data android:mimeType="image/*" />
+            </intent-filter>
+
+        </activity>
+
+        <activity android:name="org.mozilla.gecko.RobocopShare2"
+                  android:label="Robocop fake activity 2">
+
+            <intent-filter android:label="Fake robocop share handler 2">
+                <action android:name="android.intent.action.SEND" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="text/*" />
+                <data android:mimeType="image/*" />
+            </intent-filter>
+
+        </activity>
+
+        <activity android:name="org.mozilla.gecko.LaunchFennecWithConfigurationActivity"
+                  android:label="Robocop Fennec">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+    </application>
+
+</manifest>
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestGlobalSession.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestGlobalSession.java
@@ -109,17 +109,17 @@ public class TestGlobalSession {
   public void testBackoffCalledByHandleHTTPError() {
     try {
       final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
       SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), new MockSharedPreferences(), new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY));
       final GlobalSession session = new MockGlobalSession(config, callback);
 
       final HttpResponse response = new BasicHttpResponse(
         new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 503, "Illegal method/protocol"));
-      response.addHeader("X-Weave-Backoff", Long.toString(TEST_BACKOFF_IN_SECONDS)); // Backoff given in seconds.
+      response.setHeader("X-Weave-Backoff", Long.toString(TEST_BACKOFF_IN_SECONDS)); // Backoff given in seconds.
 
       getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
         @Override
         public void run() {
           session.handleHTTPError(new SyncStorageResponse(response), "Illegal method/protocol");
         }
       }));
 
@@ -240,17 +240,17 @@ public class TestGlobalSession {
     });
   }
 
   public MockGlobalSessionCallback doTestSuccess(final boolean stageShouldBackoff, final boolean stageShouldAdvance) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException {
     MockServer server = new MockServer() {
       @Override
       public void handle(Request request, Response response) {
         if (stageShouldBackoff) {
-          response.set("X-Weave-Backoff", Long.toString(TEST_BACKOFF_IN_SECONDS));
+          response.addValue("X-Weave-Backoff", Long.toString(TEST_BACKOFF_IN_SECONDS));
         }
         super.handle(request, response);
       }
     };
 
     final MockServerSyncStage stage = new MockServerSyncStage() {
       @Override
       public void execute() {
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestSyncStorageRequest.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestSyncStorageRequest.java
@@ -18,16 +18,17 @@ import org.mozilla.gecko.sync.net.SyncSt
 import org.simpleframework.http.Request;
 import org.simpleframework.http.Response;
 
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 @RunWith(TestRunner.class)
 public class TestSyncStorageRequest {
   private static final int    TEST_PORT   = HTTPServerTestHelper.getTestPort();
   private static final String TEST_SERVER = "http://localhost:" + TEST_PORT;
 
@@ -144,17 +145,17 @@ public class TestSyncStorageRequest {
       data.stopHTTPServer();
     }
   }
 
   public class RetryAfterMockServer extends MockServer {
     @Override
     public void handle(Request request, Response response) {
       String errorBody = EXPECTED_RETRY_AFTER_ERROR_MESSAGE;
-      response.set("Retry-After", "3001");
+      response.setValue("Retry-After", "3001");
       super.handle(request, response, 503, errorBody);
     }
   }
 
   @Test
   public void testRetryAfterResponse() throws URISyntaxException {
     BaseResource.rewriteLocalhost = false;
     data.startHTTPServer(new RetryAfterMockServer());
@@ -180,17 +181,17 @@ public class TestSyncStorageRequest {
       assertEquals(res.weaveBackoffInSeconds(), 1801);
       super.handleRequestSuccess(res);
     }
   }
   
   public class WeaveBackoffMockServer extends MockServer {
     @Override
     public void handle(Request request, Response response) {
-      response.set("X-Weave-Backoff", "1801");
+      response.setValue("X-Weave-Backoff", "1801");
       super.handle(request, response);
     }
   }
 
   @Test
   public void testWeaveBackoffResponse() throws URISyntaxException {
     BaseResource.rewriteLocalhost = false;
     data.startHTTPServer(new WeaveBackoffMockServer());
@@ -221,20 +222,20 @@ public class TestSyncStorageRequest {
 
       super.handleRequestSuccess(res);
     }
   }
 
   public class HeadersMockServer extends MockServer {
     @Override
     public void handle(Request request, Response response) {
-      response.set("X-Weave-Quota-Remaining", "65536");
-      response.set("X-Weave-Alert", "First weave alert string");
-      response.add("X-Weave-Alert", "Second weave alert string");
-      response.set("X-Weave-Records", "50");
+      response.setValue("X-Weave-Quota-Remaining", "65536");
+      response.setValue("X-Weave-Alert", "First weave alert string");
+      response.addValue("X-Weave-Alert", "Second weave alert string");
+      response.setValue("X-Weave-Records", "50");
 
       super.handle(request, response);
     }
   }
 
   @Test
   public void testHeadersResponse() throws URISyntaxException {
     BaseResource.rewriteLocalhost = false;
@@ -244,17 +245,17 @@ public class TestSyncStorageRequest {
     r.delegate = delegate;
     r.post(new JSONObject());
     // Server is stopped in the callback.
   }
 
   public class DeleteMockServer extends MockServer {
     @Override
     public void handle(Request request, Response response) {
-      assertTrue(request.contains("x-confirm-delete"));
+      assertNotNull(request.getValue("x-confirm-delete"));
       assertEquals("1", request.getValue("x-confirm-delete"));
       super.handle(request, response);
     }
   }
 
   @Test
   public void testDelete() throws URISyntaxException {
     BaseResource.rewriteLocalhost = false;
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/HTTPServerTestHelper.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/HTTPServerTestHelper.java
@@ -1,16 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.android.sync.test.helpers;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.BaseResourceDelegate;
+import org.simpleframework.http.core.ContainerSocketProcessor;
 import org.simpleframework.transport.connect.Connection;
 import org.simpleframework.transport.connect.SocketConnection;
 
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
 import java.util.IdentityHashMap;
 import java.util.Map;
@@ -175,17 +176,17 @@ public class HTTPServerTestHelper {
     BaseResourceDelegate.connectionTimeoutInMillis = 1000; // No sense waiting a long time for a local connection.
 
     if (!allowMultipleServers) {
       throwIfServerAlreadyRunning();
     }
 
     try {
       this.server = server;
-      connection = new SocketConnection(server);
+      connection = new SocketConnection(new ContainerSocketProcessor(server));
       SocketAddress address = new InetSocketAddress(port);
       connection.connect(address);
 
       registerServerAsRunning(this);
 
       Logger.info(LOG_TAG, "Started HTTP server on port " + port + ".");
     } catch (IOException ex) {
       Logger.error(LOG_TAG, "Error starting HTTP server on port " + port + ".", ex);
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockServer.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockServer.java
@@ -34,23 +34,23 @@ public class MockServer implements Conta
     return this.handleBasicHeaders(request, response, code, contentType, System.currentTimeMillis());
   }
 
   protected PrintStream handleBasicHeaders(Request request, Response response, int code, String contentType, long time) throws IOException {
     Logger.debug(LOG_TAG, "< Auth header: " + request.getValue("Authorization"));
 
     PrintStream bodyStream = response.getPrintStream();
     response.setCode(code);
-    response.set("Content-Type", contentType);
-    response.set("Server", "HelloWorld/1.0 (Simple 4.0)");
+    response.setValue("Content-Type", contentType);
+    response.setValue("Server", "HelloWorld/1.0 (Simple 4.0)");
     response.setDate("Date", time);
     response.setDate("Last-Modified", time);
 
     final String timestampHeader = Utils.millisecondsToDecimalSecondsString(time);
-    response.set("X-Weave-Timestamp", timestampHeader);
+    response.setValue("X-Weave-Timestamp", timestampHeader);
     Logger.debug(LOG_TAG, "> X-Weave-Timestamp header: " + timestampHeader);
     return bodyStream;
   }
 
   protected void handle(Request request, Response response, int code, String body) {
     try {
       Logger.debug(LOG_TAG, "Handling request...");
       PrintStream bodyStream = this.handleBasicHeaders(request, response, code, "application/json");
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -358,22 +358,26 @@ GlobalManager = {
         },
         hasListener(ns, name, listener) {
           return schemaApi[ns][name].hasListener.call(null, listener);
         },
       };
       Schemas.inject(chromeObj, schemaWrapper);
     };
 
-    // Find the add-on associated with this document via the
-    // principal's originAttributes. This value is computed by
-    // extensionURIToAddonID, which ensures that we don't inject our
-    // API into webAccessibleResources or remote web pages.
-    let principal = contentWindow.document.nodePrincipal;
-    let id = principal.originAttributes.addonId;
+    let id = ExtensionManagement.getAddonIdForWindow(contentWindow);
+
+    // We don't inject privileged APIs into sub-frames of a UI page.
+    const { FULL_PRIVILEGES } = ExtensionManagement.API_LEVELS;
+    if (ExtensionManagement.getAPILevelForWindow(contentWindow, id) !== FULL_PRIVILEGES) {
+      return;
+    }
+
+    // We don't inject privileged APIs if the addonId is null
+    // or doesn't exist.
     if (!this.extensionMap.has(id)) {
       return;
     }
 
     let docShell = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                                 .getInterface(Ci.nsIWebNavigation)
                                 .QueryInterface(Ci.nsIDocShellTreeItem)
                                 .sameTypeRootTreeItem
@@ -382,20 +386,16 @@ GlobalManager = {
     if (this.docShells.has(docShell)) {
       let {extension, context} = this.docShells.get(docShell);
       if (context && extension.id == id) {
         inject(extension, context);
       }
       return;
     }
 
-    // We don't inject into sub-frames of a UI page.
-    if (contentWindow != contentWindow.top) {
-      return;
-    }
     let extension = this.extensionMap.get(id);
     let uri = contentWindow.document.documentURIObject;
     let incognito = PrivateBrowsingUtils.isContentWindowPrivate(contentWindow);
     let context = new ExtensionPage(extension, {type: "tab", contentWindow, uri, docShell, incognito});
     inject(extension, context);
 
     let eventHandler = docShell.chromeEventHandler;
     let listener = event => {
--- a/toolkit/components/extensions/ExtensionContent.jsm
+++ b/toolkit/components/extensions/ExtensionContent.jsm
@@ -211,17 +211,20 @@ function getWindowMessageManager(content
   }
 }
 
 var ExtensionManager;
 
 // Scope in which extension content script code can run. It uses
 // Cu.Sandbox to run the code. There is a separate scope for each
 // frame.
-function ExtensionContext(extensionId, contentWindow) {
+function ExtensionContext(extensionId, contentWindow, contextOptions = {}) {
+  let { isExtensionPage } = contextOptions;
+
+  this.isExtensionPage = isExtensionPage;
   this.extension = ExtensionManager.get(extensionId);
   this.extensionId = extensionId;
   this.contentWindow = contentWindow;
 
   this.onClose = new Set();
 
   let utils = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                            .getInterface(Ci.nsIDOMWindowUtils);
@@ -238,44 +241,66 @@ function ExtensionContext(extensionId, c
   if (ssm.isSystemPrincipal(contentPrincipal)) {
     // Make sure we don't hand out the system principal by accident.
     prin = Cc["@mozilla.org/nullprincipal;1"].createInstance(Ci.nsIPrincipal);
   } else {
     let extensionPrincipal = ssm.createCodebasePrincipal(this.extension.baseURI, {addonId: extensionId});
     prin = [contentPrincipal, extensionPrincipal];
   }
 
-  this.sandbox = Cu.Sandbox(prin, {
-    sandboxPrototype: contentWindow,
-    wantXrays: true,
-    isWebExtensionContentScript: true,
-    wantGlobalProperties: ["XMLHttpRequest"],
-  });
+  if (isExtensionPage) {
+    if (ExtensionManagement.getAddonIdForWindow(this.contentWindow) != extensionId) {
+      throw new Error("Invalid target window for this extension context");
+    }
+    // This is an iframe with content script API enabled and its principal should be the
+    // contentWindow itself. (we create a sandbox with the contentWindow as principal and with X-rays disabled
+    // because it enables us to create the APIs object in this sandbox object and then copying it
+    // into the iframe's window, see Bug 1214658 for rationale)
+    this.sandbox = Cu.Sandbox(contentWindow, {
+      sandboxPrototype: contentWindow,
+      wantXrays: false,
+      isWebExtensionContentScript: true,
+    });
+  } else {
+    this.sandbox = Cu.Sandbox(prin, {
+      sandboxPrototype: contentWindow,
+      wantXrays: true,
+      isWebExtensionContentScript: true,
+      wantGlobalProperties: ["XMLHttpRequest"],
+    });
+  }
 
   let delegate = {
     getSender(context, target, sender) {
       // Nothing to do here.
     },
   };
 
   let url = contentWindow.location.href;
   let broker = ExtensionContent.getBroker(mm);
   // The |sender| parameter is passed directly to the extension.
   let sender = {id: this.extension.uuid, frameId, url};
   // Properties in |filter| must match those in the |recipient|
   // parameter of sendMessage.
   let filter = {extensionId, frameId};
   this.messenger = new Messenger(this, broker, sender, filter, delegate);
 
-  let chromeObj = Cu.createObjectIn(this.sandbox, {defineAs: "browser"});
+  this.chromeObj = Cu.createObjectIn(this.sandbox, {defineAs: "browser"});
 
   // Sandboxes don't get Xrays for some weird compatibility
   // reason. However, we waive here anyway in case that changes.
-  Cu.waiveXrays(this.sandbox).chrome = Cu.waiveXrays(this.sandbox).browser;
-  injectAPI(api(this), chromeObj);
+  Cu.waiveXrays(this.sandbox).chrome = this.chromeObj;
+
+  injectAPI(api(this), this.chromeObj);
+
+  // This is an iframe with content script API enabled. (See Bug 1214658 for rationale)
+  if (isExtensionPage) {
+    Cu.waiveXrays(this.contentWindow).chrome = this.chromeObj;
+    Cu.waiveXrays(this.contentWindow).browser = this.chromeObj;
+  }
 }
 
 ExtensionContext.prototype = {
   get cloneScope() {
     return this.sandbox;
   },
 
   execute(script, shouldRun) {
@@ -289,33 +314,46 @@ ExtensionContext.prototype = {
   forgetOnClose(obj) {
     this.onClose.delete(obj);
   },
 
   close() {
     for (let obj of this.onClose) {
       obj.close();
     }
+
+    // Overwrite the content script APIs with an empty object if the APIs objects are still
+    // defined in the content window (See Bug 1214658 for rationale).
+    if (this.isExtensionPage && !Cu.isDeadWrapper(this.contentWindow) &&
+        Cu.waiveXrays(this.contentWindow).browser === this.chromeObj) {
+      Cu.createObjectIn(this.contentWindow, { defineAs: "browser" });
+      Cu.createObjectIn(this.contentWindow, { defineAs: "chrome" });
+    }
+
     Cu.nukeSandbox(this.sandbox);
+    this.sandbox = null;
   },
 };
 
 function windowId(window) {
   return window.QueryInterface(Ci.nsIInterfaceRequestor)
                .getInterface(Ci.nsIDOMWindowUtils)
                .currentInnerWindowID;
 }
 
 // Responsible for creating ExtensionContexts and injecting content
 // scripts into them when new documents are created.
 var DocumentManager = {
   extensionCount: 0,
 
   // Map[windowId -> Map[extensionId -> ExtensionContext]]
-  windows: new Map(),
+  contentScriptWindows: new Map(),
+
+  // Map[windowId -> ExtensionContext]
+  extensionPageWindows: new Map(),
 
   init() {
     Services.obs.addObserver(this, "document-element-inserted", false);
     Services.obs.addObserver(this, "inner-window-destroyed", false);
   },
 
   uninit() {
     Services.obs.removeObserver(this, "document-element-inserted");
@@ -343,33 +381,50 @@ var DocumentManager = {
 
       // Make sure we only load into frames that ExtensionContent.init
       // was called on (i.e., not frames for social or sidebars).
       let mm = getWindowMessageManager(window);
       if (!mm || !ExtensionContent.globals.has(mm)) {
         return;
       }
 
+      // Enable the content script APIs should be available in subframes' window
+      // if it is recognized as a valid addon id (see Bug 1214658 for rationale).
+      const { CONTENTSCRIPT_PRIVILEGES } = ExtensionManagement.API_LEVELS;
+      let extensionId = ExtensionManagement.getAddonIdForWindow(window);
+
+      if (ExtensionManagement.getAPILevelForWindow(window, extensionId) == CONTENTSCRIPT_PRIVILEGES &&
+          ExtensionManager.get(extensionId)) {
+        DocumentManager.getExtensionPageContext(extensionId, window);
+      }
+
       this.trigger("document_start", window);
       /* eslint-disable mozilla/balanced-listeners */
       window.addEventListener("DOMContentLoaded", this, true);
       window.addEventListener("load", this, true);
       /* eslint-enable mozilla/balanced-listeners */
     } else if (topic == "inner-window-destroyed") {
-      let id = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
-      if (!this.windows.has(id)) {
-        return;
+      let windowId = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
+
+      // Close any existent content-script context for the destroyed window.
+      if (this.contentScriptWindows.has(windowId)) {
+        let extensions = this.contentScriptWindows.get(windowId);
+        for (let [, context] of extensions) {
+          context.close();
+        }
+
+        this.contentScriptWindows.delete(windowId);
       }
 
-      let extensions = this.windows.get(id);
-      for (let [, context] of extensions) {
+      // Close any existent iframe extension page context for the destroyed window.
+      if (this.extensionPageWindows.has(windowId)) {
+        let context = this.extensionWindows.get(windowId);
         context.close();
+        this.extensionPageWindows.delete(windowId);
       }
-
-      this.windows.delete(id);
     }
   },
 
   handleEvent: function(event) {
     let window = event.currentTarget;
     if (event.target != window.document) {
       // We use capturing listeners so we have precedence over content script
       // listeners, but only care about events targeted to the element we're
@@ -384,17 +439,17 @@ var DocumentManager = {
       this.trigger("document_end", window);
     } else if (event.type == "load") {
       this.trigger("document_idle", window);
     }
   },
 
   executeScript(global, extensionId, script) {
     let window = global.content;
-    let context = this.getContext(extensionId, window);
+    let context = this.getContentScriptContext(extensionId, window);
     if (!context) {
       return;
     }
 
     // TODO: Somehow make sure we have the right permissions for this origin!
 
     // FIXME: Script should be executed only if current state has
     // already reached its run_at state, or we have to keep it around
@@ -408,72 +463,95 @@ var DocumentManager = {
     yield [window, this.getWindowState(window)];
 
     for (let i = 0; i < docShell.childCount; i++) {
       let child = docShell.getChildAt(i).QueryInterface(Ci.nsIDocShell);
       yield* this.enumerateWindows(child);
     }
   },
 
-  getContext(extensionId, window) {
+  getContentScriptContext(extensionId, window) {
     let winId = windowId(window);
-    if (!this.windows.has(winId)) {
-      this.windows.set(winId, new Map());
+    if (!this.contentScriptWindows.has(winId)) {
+      this.contentScriptWindows.set(winId, new Map());
     }
-    let extensions = this.windows.get(winId);
+
+    let extensions = this.contentScriptWindows.get(winId);
     if (!extensions.has(extensionId)) {
       let context = new ExtensionContext(extensionId, window);
       extensions.set(extensionId, context);
     }
+
     return extensions.get(extensionId);
   },
 
+  getExtensionPageContext(extensionId, window) {
+    let winId = windowId(window);
+
+    let context = this.extensionPageWindows.get(winId);
+    if (!context) {
+      let context = new ExtensionContext(extensionId, window, { isExtensionPage: true });
+      this.extensionPageWindows.set(winId, context);
+    }
+
+    return context;
+  },
+
   startupExtension(extensionId) {
     if (this.extensionCount == 0) {
       this.init();
     }
     this.extensionCount++;
 
     let extension = ExtensionManager.get(extensionId);
     for (let global of ExtensionContent.globals.keys()) {
       // Note that we miss windows in the bfcache here. In theory we
       // could execute content scripts on a pageshow event for that
       // window, but that seems extreme.
       for (let [window, state] of this.enumerateWindows(global.docShell)) {
         for (let script of extension.scripts) {
           if (script.matches(window)) {
-            let context = this.getContext(extensionId, window);
+            let context = this.getContentScriptContext(extensionId, window);
             context.execute(script, scheduled => isWhenBeforeOrSame(scheduled, state));
           }
         }
       }
     }
   },
 
   shutdownExtension(extensionId) {
-    for (let [, extensions] of this.windows) {
+    // Clean up content-script contexts on extension shutdown.
+    for (let [, extensions] of this.contentScriptWindows) {
       let context = extensions.get(extensionId);
       if (context) {
         context.close();
         extensions.delete(extensionId);
       }
     }
 
+    // Clean up iframe extension page contexts on extension shutdown.
+    for (let [winId, context] of this.extensionPageWindows) {
+      if (context.extensionId == extensionId) {
+        context.close();
+        this.extensionPageWindows.delete(winId);
+      }
+    }
+
     this.extensionCount--;
     if (this.extensionCount == 0) {
       this.uninit();
     }
   },
 
   trigger(when, window) {
     let state = this.getWindowState(window);
     for (let [extensionId, extension] of ExtensionManager.extensions) {
       for (let script of extension.scripts) {
         if (script.matches(window)) {
-          let context = this.getContext(extensionId, window);
+          let context = this.getContentScriptContext(extensionId, window);
           context.execute(script, scheduled => scheduled == state);
         }
       }
     }
   },
 };
 
 // Represents a browser extension in the content process.
--- a/toolkit/components/extensions/ExtensionManagement.jsm
+++ b/toolkit/components/extensions/ExtensionManagement.jsm
@@ -197,33 +197,78 @@ var Service = {
   checkAddonMayLoad(extension, uri) {
     return extension.whiteListedHosts.matchesIgnoringPath(uri);
   },
 
   // Finds the add-on ID associated with a given moz-extension:// URI.
   // This is used to set the addonId on the originAttributes for the
   // nsIPrincipal attached to the URI.
   extensionURIToAddonID(uri) {
-    if (this.extensionURILoadableByAnyone(uri)) {
-      // We don't want webAccessibleResources to be associated with
-      // the add-on. That way they don't get any special privileges.
-      return null;
-    }
-
     let uuid = uri.host;
     let extension = this.uuidMap.get(uuid);
     return extension ? extension.id : undefined;
   },
 };
 
+// API Levels Helpers
+
+// Find the add-on associated with this document via the
+// principal's originAttributes. This value is computed by
+// extensionURIToAddonID, which ensures that we don't inject our
+// API into webAccessibleResources or remote web pages.
+function getAddonIdForWindow(window) {
+  let principal = window.document.nodePrincipal;
+  return principal.originAttributes.addonId;
+}
+
+const API_LEVELS = Object.freeze({
+  NO_PRIVILEGES: 0,
+  CONTENTSCRIPT_PRIVILEGES: 1,
+  FULL_PRIVILEGES: 2,
+});
+
+// Finds the API Level ("FULL_PRIVILEGES", "CONTENTSCRIPT_PRIVILEGES", "NO_PRIVILEGES")
+// with a given a window object.
+function getAPILevelForWindow(window, addonId) {
+  const { NO_PRIVILEGES, CONTENTSCRIPT_PRIVILEGES, FULL_PRIVILEGES } = API_LEVELS;
+
+  // Non WebExtension URLs and WebExtension URLs from a different extension
+  // has no access to APIs.
+  if (!addonId && getAddonIdForWindow(window) != addonId) {
+    return NO_PRIVILEGES;
+  }
+
+  let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
+        .getInterface(Ci.nsIDocShell);
+
+  // WebExtension URLs loaded into sub-frame UI have "content script API level privileges".
+  // (see Bug 1214658 for rationale)
+  if (docShell.sameTypeParent) {
+    return CONTENTSCRIPT_PRIVILEGES;
+  }
+
+  // Extension pages running in the content process defaults to "content script API level privileges".
+  if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
+    return CONTENTSCRIPT_PRIVILEGES;
+  }
+
+  // WebExtension URLs loaded into top frames UI could have full API level privileges.
+  return FULL_PRIVILEGES;
+}
+
 this.ExtensionManagement = {
   startupExtension: Service.startupExtension.bind(Service),
   shutdownExtension: Service.shutdownExtension.bind(Service),
 
   registerScript: Scripts.register.bind(Scripts),
   getScripts: Scripts.getScripts.bind(Scripts),
 
   registerSchema: Schemas.register.bind(Schemas),
   getSchemas: Schemas.getSchemas.bind(Schemas),
 
   getFrameId: Frames.getId.bind(Frames),
   getParentFrameId: Frames.getParentId.bind(Frames),
+
+  // exported API Level Helpers
+  getAddonIdForWindow,
+  getAPILevelForWindow,
+  API_LEVELS,
 };
rename from toolkit/components/extensions/test/mochitest/file_ext_background_api_injection.js
rename to toolkit/components/extensions/test/mochitest/file_ext_test_api_injection.js
--- a/toolkit/components/extensions/test/mochitest/mochitest.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest.ini
@@ -15,23 +15,25 @@ support-files =
   file_style_redirect.css
   file_script_good.js
   file_script_bad.js
   file_script_redirect.js
   file_script_xhr.js
   file_sample.html
   redirection.sjs
   file_privilege_escalation.html
-  file_ext_background_api_injection.js
+  file_ext_test_api_injection.js
   file_permission_xhr.html
 
 [test_ext_simple.html]
 [test_ext_geturl.html]
 [test_ext_contentscript.html]
 skip-if = buildapp == 'b2g' # runat != document_idle is not supported.
+[test_ext_contentscript_create_iframe.html]
+[test_ext_contentscript_api_injection.html]
 [test_ext_i18n_css.html]
 [test_ext_generate.html]
 [test_ext_localStorage.html]
 [test_ext_onmessage_removelistener.html]
 [test_ext_notifications.html]
 [test_ext_permission_xhr.html]
 skip-if = buildapp == 'b2g' # JavaScript error: jar:remoteopenfile:///data/local/tmp/generated-extension.xpi!/content.js, line 46: NS_ERROR_ILLEGAL_VALUE:
 [test_ext_runtime_connect.html]
--- a/toolkit/components/extensions/test/mochitest/test_ext_background_api_injection.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_background_api_injection.html
@@ -20,17 +20,17 @@ add_task(function* testBackgroundWindow(
 
       browser.test.log("background script executed");
       window.location = `${BASE}/file_privilege_escalation.html`;
     },
   });
 
   let awaitConsole = new Promise(resolve => {
     let chromeScript = SpecialPowers.loadChromeScript(
-      SimpleTest.getTestFileURL("file_ext_background_api_injection.js"));
+      SimpleTest.getTestFileURL("file_ext_test_api_injection.js"));
 
     chromeScript.addMessageListener("console-message", resolve);
   });
 
   yield extension.startup();
 
   let message = yield awaitConsole;
 
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_contentscript_api_injection.html
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for privilege escalation into iframe with content script APIs</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
+  <script type="text/javascript" src="head.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<!-- WORKAROUND: this textarea hack is used to contain the html page source without escaping it -->
+<textarea id="test-asset">
+  <!DOCTYPE HTML>
+  <html>
+    <head>
+      <meta charset="utf-8">
+      <script type="text/javascript" src="./content_script_iframe.js">
+      </script>
+    </head>
+  </html>
+</textarea>
+
+<script type="text/javascript">
+"use strict";
+
+add_task(function* test_contentscript_api_injection() {
+  function contentScript() {
+    let iframe = document.createElement("iframe");
+    iframe.setAttribute("src", browser.runtime.getURL("content_script_iframe.html"));
+    document.body.appendChild(iframe);
+  }
+
+  function contentScriptIframe() {
+    const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest";
+    window.location = `${BASE}/file_privilege_escalation.html`;
+  }
+
+  let extensionData = {
+    manifest: {
+      content_scripts: [
+        {
+          "matches": ["http://mochi.test/*/file_sample.html"],
+          "js": ["content_script.js"],
+          "run_at": "document_idle",
+        },
+      ],
+      "web_accessible_resources": [
+        "content_script_iframe.html",
+      ],
+    },
+
+    files: {
+      "content_script.js": "new " + contentScript,
+      "content_script_iframe.js": "new " + contentScriptIframe,
+      "content_script_iframe.html": document.querySelector("#test-asset").textContent,
+    },
+  };
+
+  let extension = ExtensionTestUtils.loadExtension(extensionData);
+
+  let awaitConsole = new Promise(resolve => {
+    let chromeScript = SpecialPowers.loadChromeScript(
+      SimpleTest.getTestFileURL("file_ext_test_api_injection.js"));
+
+    chromeScript.addMessageListener("console-message", resolve);
+  });
+
+  yield extension.startup();
+  info("extension loaded");
+
+  let win = window.open("file_sample.html");
+
+  let message = yield awaitConsole;
+
+  ok(message.message.includes("WebExt Privilege Escalation: typeof(browser) = undefined"),
+     "Document does not have `browser` APIs.");
+
+  win.close();
+
+  yield extension.unload();
+  info("extension unloaded");
+});
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_contentscript_create_iframe.html
@@ -0,0 +1,163 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for content script</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
+  <script type="text/javascript" src="head.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<!-- WORKAROUND: this textarea hack is used to contain the html page source without escaping it -->
+<textarea id="test-asset">
+  <!DOCTYPE HTML>
+  <html>
+    <head>
+      <meta charset="utf-8">
+      <script type="text/javascript" src="content_script_iframe.js"></script>
+    </head>
+  </html>
+</textarea>
+
+<script type="text/javascript">
+"use strict";
+
+add_task(function* test_contentscript_create_iframe() {
+  function backgroundScript() {
+    browser.runtime.onMessage.addListener((msg, sender) => {
+      let { name, availableAPIs, manifest, testGetManifest } = msg;
+      let hasExtTabsAPI = availableAPIs.indexOf("tabs") > 0;
+      let hasExtWindowsAPI = availableAPIs.indexOf("windows") > 0;
+
+      browser.test.assertFalse(hasExtTabsAPI, "the created iframe should not be able to use privileged APIs (tabs)");
+      browser.test.assertFalse(hasExtWindowsAPI, "the created iframe should not be able to use privileged APIs (windows)");
+
+      let { applications: { gecko: { id: expectedManifestGeckoId } } } = chrome.runtime.getManifest();
+      let { applications: { gecko: { id: actualManifestGeckoId } } } = manifest;
+
+      browser.test.assertEq(actualManifestGeckoId, expectedManifestGeckoId,
+                            "the add-on manifest should be accessible from the created iframe"
+      );
+
+      let { applications: { gecko: { id: testGetManifestGeckoId } } } = testGetManifest;
+
+      browser.test.assertEq(testGetManifestGeckoId, expectedManifestGeckoId,
+                              "GET_MANIFEST() returns manifest data before extension unload"
+      );
+
+      browser.test.sendMessage(name);
+    });
+  }
+
+  function contentScript() {
+    let iframe = document.createElement("iframe");
+    iframe.setAttribute("src", browser.runtime.getURL("content_script_iframe.html"));
+    document.body.appendChild(iframe);
+  }
+
+  function contentScriptIframe() {
+    window.GET_MANIFEST = browser.runtime.getManifest.bind(null);
+
+    window.testGetManifestException = () => {
+      try {
+        window.GET_MANIFEST();
+      } catch (exception) {
+        return String(exception);
+      }
+    };
+
+    let testGetManifest = window.GET_MANIFEST();
+
+    let manifest = browser.runtime.getManifest();
+    let availableAPIs = Object.keys(browser);
+
+    browser.runtime.sendMessage({
+      name: "content-script-iframe-loaded",
+      availableAPIs,
+      manifest,
+      testGetManifest,
+    });
+  }
+
+  let extensionData = {
+    manifest: {
+      content_scripts: [
+        {
+          "matches": ["http://mochi.test/*/file_sample.html"],
+          "js": ["content_script.js"],
+          "run_at": "document_idle",
+        },
+      ],
+      web_accessible_resources: [
+        "content_script_iframe.html",
+      ],
+    },
+
+    background: "(" + backgroundScript + ")()",
+
+    files: {
+      "content_script.js": "new " + contentScript,
+      "content_script_iframe.html": document.querySelector("#test-asset").textContent,
+      "content_script_iframe.js": "new " + contentScriptIframe,
+    },
+  };
+
+  let extension = ExtensionTestUtils.loadExtension(extensionData);
+
+  let contentScriptIframeCreatedPromise = new Promise(resolve => {
+    extension.onMessage("content-script-iframe-loaded", () => { resolve(); });
+  });
+
+  yield extension.startup();
+  info("extension loaded");
+
+  let win = window.open("file_sample.html");
+
+  yield Promise.all([waitForLoad(win), contentScriptIframeCreatedPromise]);
+  info("content script privileged iframe loaded and executed");
+
+  info("testing APIs availability once the extension is unloaded...");
+
+  let iframeWindow = SpecialPowers.wrap(win)[0];
+
+  ok(iframeWindow, "content script enabled iframe found");
+  ok(/content_script_iframe\.html$/.test(iframeWindow.location), "the found iframe has the expected URL");
+
+  yield extension.unload();
+  info("extension unloaded");
+
+  info("test content script APIs not accessible from the frame once the extension is unloaded");
+
+  let ww = SpecialPowers.Cu.waiveXrays(iframeWindow);
+  let isDeadWrapper = SpecialPowers.Cu.isDeadWrapper(ww.browser);
+  ok(!isDeadWrapper, "the API object should not be a dead object");
+
+  let manifest;
+  let manifestException;
+
+  try {
+    manifest = ww.browser.runtime.getManifest();
+  } catch (e) {
+    manifestException = e;
+  }
+
+  ok(!manifest, "manifest should be undefined");
+
+  is(String(manifestException), "TypeError: ww.browser.runtime is undefined",
+     "expected \"TypeError: ... is undefined\" exception received");
+
+  let getManifestException = ww.testGetManifestException();
+
+  is(getManifestException, "TypeError: window.GET_MANIFEST is not a function",
+     "expected \"TypeError: ... is not a function\" exception received");
+
+  win.close();
+
+  info("done");
+});
+</script>
+
+</body>
+</html>
--- a/toolkit/components/reader/JSDOMParser.js
+++ b/toolkit/components/reader/JSDOMParser.js
@@ -28,20 +28,16 @@
  *
  *   2) Live NodeLists are not supported. DOM methods and properties such as
  *      getElementsByTagName() and childNodes return standard arrays. If you
  *      want these lists to be updated when nodes are removed or added to the
  *      document, you must take care to manually update them yourself.
  */
 (function (global) {
 
-  function error(m) {
-    dump("JSDOMParser error: " + m + "\n");
-  }
-
   // XML only defines these and the numeric ones:
 
   var entityTable = {
     "lt": "<",
     "gt": ">",
     "amp": "&",
     "quot": '"',
     "apos": "'",
@@ -671,19 +667,19 @@
             for (var j = 0; j < child.attributes.length; j++) {
               var attr = child.attributes[j];
               // the attribute value will be HTML escaped.
               var val = attr.value;
               var quote = (val.indexOf('"') === -1 ? '"' : "'");
               arr.push(" " + attr.name + '=' + quote + val + quote);
             }
 
-            if (child.localName in voidElems) {
+            if (child.localName in voidElems && !child.childNodes.length) {
               // if this is a self-closing element, end it here
-              arr.push(">");
+              arr.push("/>");
             } else {
               // otherwise, add its children
               arr.push(">");
               getHTML(child);
               arr.push("</" + child.localName + ">");
             }
           } else {
             // This is a text node, so asking for innerHTML won't recurse.
@@ -844,19 +840,26 @@
     // over and over for this purpose uses less memory than using a new array
     // for each string.
     this.strBuf = [];
 
     // Similarly, we reuse this array to return the two arguments from
     // makeElementNode(), which saves us from having to allocate a new array
     // every time.
     this.retPair = [];
+
+    this.errorState = "";
   };
 
   JSDOMParser.prototype = {
+    error: function(m) {
+      dump("JSDOMParser error: " + m + "\n");
+      this.errorState += m + "\n";
+    },
+
     /**
      * Look at the next character without advancing the index.
      */
     peekNext: function () {
       return this.html[this.currentChar];
     },
 
     /**
@@ -901,17 +904,17 @@
       }
 
       if (!name)
         return;
 
       // After a '=', we should see a '"' for the attribute value
       var c = this.nextChar();
       if (c !== '"' && c !== "'") {
-        error("Error reading attribute " + name + ", expecting '\"'");
+        this.error("Error reading attribute " + name + ", expecting '\"'");
         return;
       }
 
       // Read the attribute value (and consume the matching quote)
       var value = this.readString(c);
 
       node.attributes.push(new Attribute(name, value));
 
@@ -954,22 +957,22 @@
         c = this.nextChar();
         if (c !== "/" && c !== ">") {
           --this.currentChar;
           this.readAttribute(node);
         }
       }
 
       // If this is a self-closing tag, read '/>'
-      var closed = tag in voidElems;
+      var closed = false;
       if (c === "/") {
         closed = true;
         c = this.nextChar();
         if (c !== ">") {
-          error("expected '>' to close " + tag);
+          this.error("expected '>' to close " + tag);
           return false;
         }
       }
 
       retPair[0] = node;
       retPair[1] = closed;
       return true
     },
@@ -1129,17 +1132,17 @@
       if (!closed) {
         if (localName == "script") {
           this.readScript(node);
         } else {
           this.readChildren(node);
         }
         var closingTag = "</" + localName + ">";
         if (!this.match(closingTag)) {
-          error("expected '" + closingTag + "'");
+          this.error("expected '" + closingTag + "' and got " + this.html.substr(this.currentChar, closingTag.length));
           return null;
         }
       }
 
       // Only use the first title, because SVG might have other
       // title elements which we don't care about (medium.com
       // does this, at least).
       if (localName === "title" && !this.doc.title) {
--- a/toolkit/components/reader/Readability.js
+++ b/toolkit/components/reader/Readability.js
@@ -112,17 +112,17 @@ Readability.prototype = {
   DEFAULT_TAGS_TO_SCORE: "section,h2,h3,h4,h5,h6,p,td,pre".toUpperCase().split(","),
 
   // All of the regular expressions in use within readability.
   // Defined up here so we don't instantiate them repeatedly in loops.
   REGEXPS: {
     unlikelyCandidates: /banner|combx|comment|community|disqus|extra|foot|header|menu|related|remark|rss|share|shoutbox|sidebar|skyscraper|sponsor|ad-break|agegate|pagination|pager|popup/i,
     okMaybeItsACandidate: /and|article|body|column|main|shadow/i,
     positive: /article|body|content|entry|hentry|main|page|pagination|post|text|blog|story/i,
-    negative: /hidden|banner|combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i,
+    negative: /hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i,
     extraneous: /print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i,
     byline: /byline|author|dateline|writtenby/i,
     replaceFonts: /<(\/?)font[^>]*>/gi,
     normalize: /\s{2,}/g,
     videos: /\/\/(www\.)?(dailymotion|youtube|youtube-nocookie|player\.vimeo)\.com/i,
     nextLink: /(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i,
     prevLink: /(prev|earl|old|new|<|«)/i,
     whitespace: /^\s*$/,
--- a/toolkit/modules/AppConstants.jsm
+++ b/toolkit/modules/AppConstants.jsm
@@ -242,16 +242,37 @@ this.AppConstants = Object.freeze({
 
   MOZ_PLACES:
 #ifdef MOZ_PLACES
   true,
 #else
   false,
 #endif
 
+  MOZ_REQUIRE_SIGNING:
+#ifdef MOZ_REQUIRE_SIGNING
+  true,
+#else
+  false,
+#endif
+
+  MENUBAR_CAN_AUTOHIDE:
+#ifdef MENUBAR_CAN_AUTOHIDE
+  true,
+#else
+  false,
+#endif
+
+  CAN_DRAW_IN_TITLEBAR:
+#ifdef CAN_DRAW_IN_TITLEBAR
+  true,
+#else
+  false,
+#endif
+
   MOZ_ANDROID_HISTORY:
 #ifdef MOZ_ANDROID_HISTORY
   true,
 #else
   false,
 #endif
 
   DLL_PREFIX: "@DLL_PREFIX@",
--- a/toolkit/modules/moz.build
+++ b/toolkit/modules/moz.build
@@ -76,16 +76,22 @@ EXTRA_JS_MODULES += [
     'Timer.jsm',
     'Troubleshoot.jsm',
     'UpdateUtils.jsm',
     'WebChannel.jsm',
     'WindowDraggingUtils.jsm',
     'ZipUtils.jsm',
 ]
 
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
+    DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'):
+    DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1
+
 EXTRA_PP_JS_MODULES += [
     'AppConstants.jsm',
 ]
 
 if 'Android' != CONFIG['OS_TARGET']:
     EXTRA_JS_MODULES += [
         'LightweightThemeConsumer.jsm',
     ]
@@ -106,11 +112,12 @@ for var in ('ANDROID_PACKAGE_NAME',
             'MOZ_WIDGET_TOOLKIT',
             'DLL_PREFIX',
             'DLL_SUFFIX',
             'DEBUG_JS_MODULES',
             'SOURCE_REV_URL'):
             DEFINES[var] = CONFIG[var]
 
 for var in ('MOZ_TOOLKIT_SEARCH',
+            'MOZ_REQUIRE_SIGNING',
             'MOZ_UPDATER'):
     if CONFIG[var]:
         DEFINES[var] = True