Merge m-c to inbound, a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 19 Sep 2016 15:56:30 -0700
changeset 314461 01c1466180b014bec1cdcb951068a57287a04b15
parent 314460 b6fda98133de09b80069e0b921c866b6a0ee7e86 (current diff)
parent 314407 c9971be9e98150ef99d4ef80c6f800ec5915b1ac (diff)
child 314462 1b269fb8a704a1a1fd2fe67543b9a083ce155563
push id20574
push usercbook@mozilla.com
push dateTue, 20 Sep 2016 10:05:16 +0000
treeherderfx-team@14705f779a46 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone52.0a1
Merge m-c to inbound, a=merge
--- a/.hgtags
+++ b/.hgtags
@@ -123,8 +123,9 @@ 7a19194812eb767bee7cdf8fc36ba9a383c1bead
 fcef8ded82219c89298b4e376cfbdfba79a1d35a FIREFOX_AURORA_43_BASE
 67a788db9f07822cfef52351bbbe3745dff8bd7f FIREFOX_AURORA_44_BASE
 99137d6d4061f408ae0869122649d8bdf489cc30 FIREFOX_AURORA_45_BASE
 67c66c2878aed17ae3096d7db483ddbb2293c503 FIREFOX_AURORA_46_BASE
 68d3781deda0d4d58ec9877862830db89669b3a5 FIREFOX_AURORA_47_BASE
 1c6385ae1fe7e37d8f23f958ce14582f07af729e FIREFOX_AURORA_48_BASE
 d98f20c25feeac4dd7ebbd1c022957df1ef58af4 FIREFOX_AURORA_49_BASE
 465d150bc8be5bbf9f02a8607d4552b6a5e1697c FIREFOX_AURORA_50_BASE
+fc69febcbf6c0dcc4b3dfc7a346d8d348798a65f FIREFOX_AURORA_51_BASE
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1297097 - Remove preference "layout.css.vertical-text.enabled" modifies nsCSSPropList.h. Might need a clobber due to bug 1276197.
+Merge day clobber
\ No newline at end of file
--- a/browser/base/content/browser-media.js
+++ b/browser/base/content/browser-media.js
@@ -291,17 +291,17 @@ let gDecoderDoctorHandler = {
       if (!formatsInPref) {
         Services.prefs.setCharPref(formatsPref, formats);
         histogram.add(decoderDoctorReportId, TELEMETRY_DDSTAT_SHOWN_FIRST);
       } else {
         // Split existing formats into an array of strings.
         let existing = formatsInPref.split(",").map(String.trim);
         // Keep given formats that were not already recorded.
         let newbies = formats.split(",").map(String.trim)
-                      .filter(x => existing.includes(x));
+                      .filter(x => !existing.includes(x));
         // And rewrite pref with the added new formats (if any).
         if (newbies.length) {
           Services.prefs.setCharPref(formatsPref,
                                      existing.concat(newbies).join(", "));
         }
       }
       histogram.add(decoderDoctorReportId, TELEMETRY_DDSTAT_SHOWN);
 
--- a/browser/components/preferences/connection.xul
+++ b/browser/components/preferences/connection.xul
@@ -9,17 +9,22 @@
 <?xml-stylesheet href="chrome://global/skin/"?>
 
 <prefwindow id="ConnectionsDialog" type="child"
             xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
             title="&connectionsDialog.title;"
             dlgbuttons="accept,cancel,help"
             onbeforeaccept="return gConnectionsDialog.beforeAccept();"
             onload="gConnectionsDialog.checkForSystemProxy();"
-            ondialoghelp="openPrefsHelp()">
+            ondialoghelp="openPrefsHelp()"
+#ifdef XP_MACOSX
+            style="width: &window.macWidth2; !important;">
+#else
+            style="width: &window.width2; !important;">
+#endif
 
   <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
 
   <prefpane id="ConnectionsDialogPane"
             class="largeDialogContainer"
             helpTopic="prefs-connection-settings">
 
     <preferences>
--- a/browser/components/preferences/jar.mn
+++ b/browser/components/preferences/jar.mn
@@ -5,17 +5,17 @@
 browser.jar:
     content/browser/preferences/applicationManager.xul
     content/browser/preferences/applicationManager.js
     content/browser/preferences/blocklists.xul
     content/browser/preferences/blocklists.js
 *   content/browser/preferences/colors.xul
 *   content/browser/preferences/cookies.xul
     content/browser/preferences/cookies.js
-    content/browser/preferences/connection.xul
+*   content/browser/preferences/connection.xul
     content/browser/preferences/connection.js
     content/browser/preferences/donottrack.xul
 *   content/browser/preferences/fonts.xul
     content/browser/preferences/fonts.js
     content/browser/preferences/handlers.xml
     content/browser/preferences/handlers.css
 *   content/browser/preferences/languages.xul
     content/browser/preferences/languages.js
--- a/browser/config/version.txt
+++ b/browser/config/version.txt
@@ -1,1 +1,1 @@
-51.0a1
+52.0a1
--- a/browser/config/version_display.txt
+++ b/browser/config/version_display.txt
@@ -1,1 +1,1 @@
-51.0a1
+52.0a1
--- a/browser/locales/en-US/chrome/browser/preferences/connection.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/connection.dtd
@@ -1,14 +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/. -->
 
 
 <!ENTITY  connectionsDialog.title       "Connection Settings">
+<!ENTITY  window.width2                 "49em">
+<!ENTITY  window.macWidth2              "44em">
 
 <!ENTITY  proxyTitle.label              "Configure Proxies to Access the Internet">
 <!ENTITY  noProxyTypeRadio.label        "No proxy">
 <!ENTITY  noProxyTypeRadio.accesskey    "y">
 <!ENTITY  systemTypeRadio.label         "Use system proxy settings">
 <!ENTITY  systemTypeRadio.accesskey     "u">
 <!ENTITY  WPADTypeRadio.label           "Auto-detect proxy settings for this network">
 <!ENTITY  WPADTypeRadio.accesskey       "w">
--- a/browser/modules/SitePermissions.jsm
+++ b/browser/modules/SitePermissions.jsm
@@ -19,29 +19,35 @@ this.SitePermissions = {
   /* Returns all custom permissions for a given URI, the return
    * type is a list of objects with the keys:
    * - id: the permissionId of the permission
    * - state: a constant representing the current permission state
    *   (e.g. SitePermissions.ALLOW)
    *
    * To receive a more detailed, albeit less performant listing see
    * SitePermissions.getPermissionDetailsByURI().
+   *
+   * install addon permission is excluded, check bug 1303108
    */
   getAllByURI: function (aURI) {
     let result = [];
     if (!this.isSupportedURI(aURI)) {
       return result;
     }
 
     let permissions = Services.perms.getAllForURI(aURI);
     while (permissions.hasMoreElements()) {
       let permission = permissions.getNext();
 
       // filter out unknown permissions
       if (gPermissionObject[permission.type]) {
+        // XXX Bug 1303108 - Control Center should only show non-default permissions
+        if (permission.type == "install") {
+          continue;
+        }
         result.push({
           id: permission.type,
           state: permission.capability,
         });
       }
     }
 
     return result;
--- a/browser/modules/test/xpcshell/test_SitePermissions.js
+++ b/browser/modules/test/xpcshell/test_SitePermissions.js
@@ -40,16 +40,21 @@ add_task(function* testGetAllByURI() {
   Assert.deepEqual(SitePermissions.getAllByURI(uri), [
       { id: "camera", state: SitePermissions.ALLOW },
       { id: "desktop-notification", state: SitePermissions.BLOCK }
   ]);
 
   SitePermissions.remove(uri, "camera");
   SitePermissions.remove(uri, "desktop-notification");
   Assert.deepEqual(SitePermissions.getAllByURI(uri), []);
+
+  // XXX Bug 1303108 - Control Center should only show non-default permissions
+  SitePermissions.set(uri, "addon", SitePermissions.BLOCK);
+  Assert.deepEqual(SitePermissions.getAllByURI(uri), []);
+  SitePermissions.remove(uri, "addon");
 });
 
 add_task(function* testGetPermissionDetailsByURI() {
   // check that it returns an empty array on an invalid URI
   // like a file URI, which doesn't support site permissions
   let wrongURI = Services.io.newURI("file:///example.js", null, null)
   Assert.deepEqual(SitePermissions.getPermissionDetailsByURI(wrongURI), []);
 
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Preferences.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Preferences.jsm
@@ -23,19 +23,21 @@ this.Preferences = {
       ["paneApplications", null],
       ["panePrivacy", null],
       ["panePrivacy", null, DNTDialog],
       ["paneSecurity", null],
       ["paneSync", null],
       ["paneAdvanced", "generalTab"],
       ["paneAdvanced", "dataChoicesTab"],
       ["paneAdvanced", "networkTab"],
+      ["paneAdvanced", "networkTab", connectionDialog],
       ["paneAdvanced", "updateTab"],
       ["paneAdvanced", "encryptionTab"],
       ["paneAdvanced", "encryptionTab", certManager],
+      ["paneAdvanced", "encryptionTab", deviceManager],
     ];
     for (let [primary, advanced, customFn] of panes) {
       let configName = primary.replace(/^pane/, "prefs") + (advanced ? "-" + advanced : "");
       if (customFn) {
         configName += "-" + customFn.name;
       }
       this.configurations[configName] = {};
       this.configurations[configName].applyConfig = prefHelper.bind(null, primary, advanced, customFn);
@@ -94,13 +96,25 @@ function paintPromise(browserWindow) {
 }
 
 function* DNTDialog(aBrowser) {
   yield ContentTask.spawn(aBrowser, null, function* () {
     content.document.getElementById("doNotTrackSettings").click();
   });
 }
 
+function* connectionDialog(aBrowser) {
+  yield ContentTask.spawn(aBrowser, null, function* () {
+    content.document.getElementById("connectionSettings").click();
+  });
+}
+
 function* certManager(aBrowser) {
   yield ContentTask.spawn(aBrowser, null, function* () {
     content.document.getElementById("viewCertificatesButton").click();
   });
 }
+
+function* deviceManager(aBrowser) {
+  yield ContentTask.spawn(aBrowser, null, function* () {
+    content.document.getElementById("viewSecurityDevicesButton").click();
+  });
+}
--- a/build/autoconf/android.m4
+++ b/build/autoconf/android.m4
@@ -216,18 +216,18 @@ if test -n "$MOZ_INSTALL_TRACKING"; then
     AC_SUBST(MOZ_INSTALL_TRACKING)
     MOZ_ANDROID_AAR(play-services-ads, $ANDROID_GOOGLE_PLAY_SERVICES_VERSION, google, com/google/android/gms)
     MOZ_ANDROID_AAR(play-services-basement, $ANDROID_GOOGLE_PLAY_SERVICES_VERSION, google, com/google/android/gms)
 fi
 
 ])
 
 dnl Configure an Android SDK.
-dnl Arg 1: target SDK version, like 22.
-dnl Arg 2: build tools version, like 22.0.1.
+dnl Arg 1: target SDK version, like 23.
+dnl Arg 2: list of build-tools versions, like "23.0.3 23.0.1".
 AC_DEFUN([MOZ_ANDROID_SDK],
 [
 
 MOZ_ARG_WITH_STRING(android-sdk,
 [  --with-android-sdk=DIR
                           location where the Android SDK can be found (like ~/.mozbuild/android-sdk-linux)],
     android_sdk_root=$withval)
 
@@ -249,22 +249,30 @@ case "$target" in
     android_target_sdk=$1
     AC_MSG_CHECKING([for Android SDK platform version $android_target_sdk])
     android_sdk=$android_sdk_root/platforms/android-$android_target_sdk
     if ! test -e "$android_sdk/source.properties" ; then
         AC_MSG_ERROR([You must download Android SDK platform version $android_target_sdk.  Try |mach bootstrap|.  (Looked for $android_sdk)])
     fi
     AC_MSG_RESULT([$android_sdk])
 
-    android_build_tools="$android_sdk_root"/build-tools/$2
-    AC_MSG_CHECKING([for Android build-tools version $2])
-    if test -d "$android_build_tools" -a -f "$android_build_tools/aapt"; then
-        AC_MSG_RESULT([$android_build_tools])
-    else
-        AC_MSG_ERROR([You must install the Android build-tools version $2.  Try |mach bootstrap|.  (Looked for $android_build_tools)])
+    AC_MSG_CHECKING([for Android build-tools])
+    android_build_tools_base="$android_sdk_root"/build-tools
+    android_build_tools_version=""
+    for version in $2; do
+        android_build_tools="$android_build_tools_base"/$version
+        if test -d "$android_build_tools" -a -f "$android_build_tools/aapt"; then
+            android_build_tools_version=$version
+            AC_MSG_RESULT([$android_build_tools])
+            break
+        fi
+    done
+    if test "$android_build_tools_version" == ""; then
+        version=$(echo $2 | cut -d" " -f1)
+        AC_MSG_ERROR([You must install the Android build-tools version $version.  Try |mach bootstrap|.  (Looked for "$android_build_tools_base"/$version)])
     fi
 
     MOZ_PATH_PROG(ZIPALIGN, zipalign, :, [$android_build_tools])
     MOZ_PATH_PROG(DX, dx, :, [$android_build_tools])
     MOZ_PATH_PROG(AAPT, aapt, :, [$android_build_tools])
     MOZ_PATH_PROG(AIDL, aidl, :, [$android_build_tools])
     if test -z "$ZIPALIGN" -o "$ZIPALIGN" = ":"; then
       AC_MSG_ERROR([The program zipalign was not found.  Try |mach bootstrap|.])
@@ -304,17 +312,17 @@ case "$target" in
     if test -z "$EMULATOR" -o "$EMULATOR" = ":"; then
       AC_MSG_ERROR([The program emulator was not found.  Try |mach bootstrap|.])
     fi
 
     ANDROID_TARGET_SDK="${android_target_sdk}"
     ANDROID_SDK="${android_sdk}"
     ANDROID_SDK_ROOT="${android_sdk_root}"
     ANDROID_TOOLS="${android_tools}"
-    ANDROID_BUILD_TOOLS_VERSION="$2"
+    ANDROID_BUILD_TOOLS_VERSION="$android_build_tools_version"
     AC_DEFINE_UNQUOTED(ANDROID_TARGET_SDK,$ANDROID_TARGET_SDK)
     AC_SUBST(ANDROID_TARGET_SDK)
     AC_SUBST(ANDROID_SDK_ROOT)
     AC_SUBST(ANDROID_SDK)
     AC_SUBST(ANDROID_TOOLS)
     AC_SUBST(ANDROID_BUILD_TOOLS_VERSION)
 
     MOZ_ANDROID_AAR(customtabs, $ANDROID_SUPPORT_LIBRARY_VERSION, android, com/android/support)
--- a/config/milestone.txt
+++ b/config/milestone.txt
@@ -5,9 +5,9 @@
 #    x.x.x.x
 #    x.x.x+
 #
 # Referenced by milestone.py.
 # Hopefully I'll be able to automate replacement of *all*
 # hardcoded milestones in the tree from these two files.
 #--------------------------------------------------------
 
-51.0a1
+52.0a1
--- a/devtools/client/framework/toolbox-process-window.xul
+++ b/devtools/client/framework/toolbox-process-window.xul
@@ -36,10 +36,12 @@
   <!-- This will be used by the Web Console to hold any popups it may create,
        for example when viewing network request details. -->
   <popupset id="mainPopupSet"></popupset>
 
   <vbox id="error-message-container" hidden="true" flex="1">
     <box>&browserToolboxErrorMessage;</box>
     <textbox multiline="true" id="error-message" flex="1"></textbox>
   </vbox>
-  <iframe id="toolbox-iframe" flex="1"></iframe>
+
+  <tooltip id="aHTMLTooltip" page="true"/>
+  <iframe id="toolbox-iframe" flex="1" tooltip="aHTMLTooltip"></iframe>
 </window>
--- a/devtools/client/responsive.html/manager.js
+++ b/devtools/client/responsive.html/manager.js
@@ -300,18 +300,19 @@ ResponsiveUI.prototype = {
    * to ensure all in-page state is preserved, just like when you move a tab to
    * a new window.
    *
    * For more details, see /devtools/docs/responsive-design-mode.md.
    */
   init: Task.async(function* () {
     let ui = this;
 
-    // Watch for tab close so we can clean up RDM synchronously
+    // Watch for tab close and window close so we can clean up RDM synchronously
     this.tab.addEventListener("TabClose", this);
+    this.browserWindow.addEventListener("unload", this);
 
     // Swap page content from the current tab into a viewport within RDM
     this.swap = swapToInnerBrowser({
       tab: this.tab,
       containerURL: TOOL_URL,
       getInnerBrowser: Task.async(function* (containerBrowser) {
         let toolWindow = ui.toolWindow = containerBrowser.contentWindow;
         toolWindow.addEventListener("message", ui);
@@ -343,24 +344,26 @@ ResponsiveUI.prototype = {
     if (this.destroying) {
       return false;
     }
     this.destroying = true;
 
     // If our tab is about to be closed, there's not enough time to exit
     // gracefully, but that shouldn't be a problem since the tab will go away.
     // So, skip any yielding when we're about to close the tab.
-    let isTabClosing = options && options.reason == "TabClose";
+    let isWindowClosing = options && options.reason === "unload";
+    let isTabClosing = (options && options.reason === "TabClose") || isWindowClosing;
 
     // Ensure init has finished before starting destroy
     if (!isTabClosing) {
       yield this.inited;
     }
 
     this.tab.removeEventListener("TabClose", this);
+    this.browserWindow.removeEventListener("unload", this);
     this.toolWindow.removeEventListener("message", this);
 
     if (!isTabClosing) {
       // Stop the touch event simulator if it was running
       yield this.emulationFront.clearTouchEventsOverride();
 
       // Notify the inner browser to stop the frame script
       yield message.request(this.toolWindow, "stop-frame-script");
@@ -376,18 +379,20 @@ ResponsiveUI.prototype = {
 
     // Close the debugger client used to speak with emulation actor
     let clientClosed = this.client.close();
     if (!isTabClosing) {
       yield clientClosed;
     }
     this.client = this.emulationFront = null;
 
-    // Undo the swap and return the content back to a normal tab
-    swap.stop();
+    if (!isWindowClosing) {
+      // Undo the swap and return the content back to a normal tab
+      swap.stop();
+    }
 
     this.destroyed = true;
 
     return true;
   }),
 
   connectToServer: Task.async(function* () {
     if (!DebuggerServer.initialized) {
@@ -402,16 +407,17 @@ ResponsiveUI.prototype = {
 
   handleEvent(event) {
     let { browserWindow, tab } = this;
 
     switch (event.type) {
       case "message":
         this.handleMessage(event);
         break;
+      case "unload":
       case "TabClose":
         ResponsiveUIManager.closeIfNeeded(browserWindow, tab, {
           reason: event.type,
         });
         break;
     }
   },
 
--- a/devtools/client/responsive.html/test/browser/browser.ini
+++ b/devtools/client/responsive.html/test/browser/browser.ini
@@ -3,16 +3,17 @@ tags = devtools
 subsuite = devtools
 # !e10s: RDM only works for remote tabs
 skip-if = !e10s
 support-files =
   devices.json
   doc_page_state.html
   geolocation.html
   head.js
+  touch.html
   !/devtools/client/commandline/test/helpers.js
   !/devtools/client/framework/test/shared-head.js
   !/devtools/client/framework/test/shared-redux-head.js
   !/devtools/client/inspector/test/shared-head.js
   !/devtools/client/shared/test/test-actor.js
   !/devtools/client/shared/test/test-actor-registry.js
 
 [browser_device_change.js]
@@ -31,8 +32,9 @@ support-files =
 [browser_resize_cmd.js]
 [browser_screenshot_button.js]
 [browser_shutdown_close_sync.js]
 [browser_toolbox_computed_view.js]
 [browser_toolbox_rule_view.js]
 [browser_toolbox_swap_browsers.js]
 [browser_touch_simulation.js]
 [browser_viewport_basics.js]
+[browser_window_close.js]
--- a/devtools/client/responsive.html/test/browser/browser_touch_simulation.js
+++ b/devtools/client/responsive.html/test/browser/browser_touch_simulation.js
@@ -1,25 +1,240 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test global touch simulation button
 
-const TEST_URL = "data:text/html;charset=utf-8,";
+const TEST_URL = `${URL_ROOT}touch.html`;
+const PREF_DOM_META_VIEWPORT_ENABLED = "dom.meta-viewport.enabled";
 
 addRDMTask(TEST_URL, function* ({ ui }) {
-  let { store, document } = ui.toolWindow;
-  let touchButton = document.querySelector("#global-touch-simulation-button");
+  yield waitBootstrap(ui);
+  yield testWithNoTouch(ui);
+  yield enableTouchSimulation(ui);
+  yield testWithTouch(ui);
+  yield testWithMetaViewportEnabled(ui);
+  yield testWithMetaViewportDisabled(ui);
+  testTouchButton(ui);
+});
+
+function* testWithNoTouch(ui) {
+  yield injectEventUtils(ui);
+  yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
+    let { EventUtils } = content;
+
+    let div = content.document.querySelector("div");
+    let x = 0, y = 0;
+
+    info("testWithNoTouch: Initial test parameter and mouse mouse outside div");
+    x = -1; y = -1;
+    yield EventUtils.synthesizeMouse(div, x, y,
+          { type: "mousemove", isSynthesized: false }, content);
+    div.style.transform = "none";
+    div.style.backgroundColor = "";
+
+    info("testWithNoTouch: Move mouse into the div element");
+    yield EventUtils.synthesizeMouseAtCenter(div,
+          { type: "mousemove", isSynthesized: false }, content);
+    is(div.style.backgroundColor, "red", "mouseenter or mouseover should work");
+
+    info("testWithNoTouch: Drag the div element");
+    yield EventUtils.synthesizeMouseAtCenter(div,
+          { type: "mousedown", isSynthesized: false }, content);
+    x = 100; y = 100;
+    yield EventUtils.synthesizeMouse(div, x, y,
+          { type: "mousemove", isSynthesized: false }, content);
+    is(div.style.transform, "none", "touchmove shouldn't work");
+    yield EventUtils.synthesizeMouse(div, x, y,
+          { type: "mouseup", isSynthesized: false }, content);
+
+    info("testWithNoTouch: Move mouse out of the div element");
+    x = -1; y = -1;
+    yield EventUtils.synthesizeMouse(div, x, y,
+          { type: "mousemove", isSynthesized: false }, content);
+    is(div.style.backgroundColor, "blue", "mouseout or mouseleave should work");
+
+    info("testWithNoTouch: Click the div element");
+    yield EventUtils.synthesizeClick(div);
+    is(div.dataset.isDelay, "false",
+      "300ms delay between touch events and mouse events should not work");
+  });
+}
+
+function* testWithTouch(ui) {
+  yield injectEventUtils(ui);
+
+  yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
+    let { EventUtils } = content;
+
+    let div = content.document.querySelector("div");
+    let x = 0, y = 0;
+
+    info("testWithTouch: Initial test parameter and mouse mouse outside div");
+    x = -1; y = -1;
+    yield EventUtils.synthesizeMouse(div, x, y,
+          { type: "mousemove", isSynthesized: false }, content);
+    div.style.transform = "none";
+    div.style.backgroundColor = "";
+
+    info("testWithTouch: Move mouse into the div element");
+    yield EventUtils.synthesizeMouseAtCenter(div,
+          { type: "mousemove", isSynthesized: false }, content);
+    isnot(div.style.backgroundColor, "red",
+      "mouseenter or mouseover should not work");
 
-  // Wait until the viewport has been added
-  yield waitUntilState(store, state => state.viewports.length == 1);
-  yield waitForFrameLoad(ui, TEST_URL);
+    info("testWithTouch: Drag the div element");
+    yield EventUtils.synthesizeMouseAtCenter(div,
+          { type: "mousedown", isSynthesized: false }, content);
+    x = 100; y = 100;
+    yield EventUtils.synthesizeMouse(div, x, y,
+          { type: "mousemove", isSynthesized: false }, content);
+    isnot(div.style.transform, "none", "touchmove should work");
+    yield EventUtils.synthesizeMouse(div, x, y,
+          { type: "mouseup", isSynthesized: false }, content);
+
+    info("testWithTouch: Move mouse out of the div element");
+    x = -1; y = -1;
+    yield EventUtils.synthesizeMouse(div, x, y,
+          { type: "mousemove", isSynthesized: false }, content);
+    isnot(div.style.backgroundColor, "blue",
+      "mouseout or mouseleave should not work");
+  });
+}
+
+function* testWithMetaViewportEnabled(ui) {
+  yield SpecialPowers.pushPrefEnv({set: [[PREF_DOM_META_VIEWPORT_ENABLED, true]]});
+
+  yield injectEventUtils(ui);
+
+  yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
+    let { synthesizeClick } = content.EventUtils;
+
+    let meta = content.document.querySelector("meta[name=viewport]");
+    let div = content.document.querySelector("div");
+    div.dataset.isDelay = "false";
+
+    info("testWithMetaViewportEnabled: " +
+         "click the div element with <meta name='viewport'>");
+    meta.content = "";
+    yield synthesizeClick(div);
+    is(div.dataset.isDelay, "true",
+      "300ms delay between touch events and mouse events should work");
+
+    info("testWithMetaViewportEnabled: " +
+         "click the div element with " +
+         "<meta name='viewport' content='user-scalable=no'>");
+    meta.content = "user-scalable=no";
+    yield synthesizeClick(div);
+    is(div.dataset.isDelay, "false",
+      "300ms delay between touch events and mouse events should not work");
+
+    info("testWithMetaViewportEnabled: " +
+         "click the div element with " +
+         "<meta name='viewport' content='minimum-scale=maximum-scale'>");
+    meta.content = "minimum-scale=maximum-scale";
+    yield synthesizeClick(div);
+    is(div.dataset.isDelay, "false",
+      "300ms delay between touch events and mouse events should not work");
+
+    info("testWithMetaViewportEnabled: " +
+         "click the div element with " +
+         "<meta name='viewport' content='width=device-width'>");
+    meta.content = "width=device-width";
+    yield synthesizeClick(div);
+    is(div.dataset.isDelay, "false",
+      "300ms delay between touch events and mouse events should not work");
+  });
+}
+
+function* testWithMetaViewportDisabled(ui) {
+  yield SpecialPowers.pushPrefEnv({set: [[PREF_DOM_META_VIEWPORT_ENABLED, false]]});
+
+  yield injectEventUtils(ui);
+
+  yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
+    let { synthesizeClick } = content.EventUtils;
+
+    let meta = content.document.querySelector("meta[name=viewport]");
+    let div = content.document.querySelector("div");
+    div.dataset.isDelay = "false";
+
+    info("testWithMetaViewportDisabled: click the div with <meta name='viewport'>");
+    meta.content = "";
+    yield synthesizeClick(div);
+    is(div.dataset.isDelay, "true",
+      "300ms delay between touch events and mouse events should work");
+  });
+}
+
+function testTouchButton(ui) {
+  let { document } = ui.toolWindow;
+  let touchButton = document.querySelector("#global-touch-simulation-button");
 
   ok(!touchButton.classList.contains("active"),
     "Touch simulation is not active by default.");
 
   touchButton.click();
 
   ok(touchButton.classList.contains("active"),
     "Touch simulation is started on click.");
-});
+
+  touchButton.click();
+
+  ok(!touchButton.classList.contains("active"),
+    "Touch simulation is stopped on click.");
+}
+
+function* waitBootstrap(ui) {
+  let { store } = ui.toolWindow;
+
+  yield waitUntilState(store, state => state.viewports.length == 1);
+  yield waitForFrameLoad(ui, TEST_URL);
+}
+
+function* injectEventUtils(ui) {
+  yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
+    if ("EventUtils" in content) {
+      return;
+    }
+
+    let EventUtils = content.EventUtils = {};
+
+    EventUtils.window = {};
+    EventUtils.parent = EventUtils.window;
+    /* eslint-disable camelcase */
+    EventUtils._EU_Ci = Components.interfaces;
+    EventUtils._EU_Cc = Components.classes;
+    /* eslint-enable camelcase */
+    // EventUtils' `sendChar` function relies on the navigator to synthetize events.
+    EventUtils.navigator = content.navigator;
+    EventUtils.KeyboardEvent = content.KeyboardEvent;
+
+    EventUtils.synthesizeClick = element => new Promise(resolve => {
+      element.addEventListener("click", function onClick() {
+        element.removeEventListener("click", onClick);
+        resolve();
+      });
+
+      EventUtils.synthesizeMouseAtCenter(element,
+        { type: "mousedown", isSynthesized: false }, content);
+      EventUtils.synthesizeMouseAtCenter(element,
+        { type: "mouseup", isSynthesized: false }, content);
+    });
+
+    Services.scriptloader.loadSubScript(
+      "chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
+  });
+}
+
+const enableTouchSimulation = ui => new Promise(
+  Task.async(function* (resolve) {
+    let browser = ui.getViewportBrowser();
+
+    browser.addEventListener("mozbrowserloadend", function onLoad() {
+      browser.removeEventListener("mozbrowserloadend", onLoad);
+      resolve();
+    });
+
+    yield ui.updateTouchSimulation(true);
+  }));
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/test/browser/browser_window_close.js
@@ -0,0 +1,25 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(function* () {
+  let newWindowPromise = BrowserTestUtils.waitForNewWindow();
+  window.open("data:text/html;charset=utf-8,", "_blank");
+  let newWindow = yield newWindowPromise;
+
+  newWindow.focus();
+  yield once(newWindow.gBrowser, "load", true);
+
+  let tab = newWindow.gBrowser.selectedTab;
+  yield openRDM(tab);
+
+  // Close the window on a tab with an active responsive design UI and
+  // wait for the UI to gracefully shutdown.  This has leaked the window
+  // in the past.
+  ok(ResponsiveUIManager.isActiveForTab(tab),
+     "ResponsiveUI should be active for tab when the window is closed");
+  let offPromise = once(ResponsiveUIManager, "off");
+  yield BrowserTestUtils.closeWindow(newWindow);
+  yield offPromise;
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/test/browser/touch.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+
+<meta charset="utf-8" />
+<meta name="viewport" />
+<title>test</title>
+
+
+<style>
+  div {
+    border :1px solid red;
+    width: 100px; height: 100px;
+  }
+</style>
+
+<div data-is-delay="false"></div>
+
+<script type="text/javascript;version=1.8">
+  "use strict";
+  let div = document.querySelector("div");
+  let initX, initY;
+  let previousEvent = "", touchendTime = 0;
+  let updatePreviousEvent = function (e) {
+    previousEvent = e.type;
+  };
+
+  div.style.transform = "none";
+  div.style.backgroundColor = "";
+
+  div.addEventListener("touchstart", function (evt) {
+    let touch = evt.changedTouches[0];
+    initX = touch.pageX;
+    initY = touch.pageY;
+    updatePreviousEvent(evt);
+  }, true);
+
+  div.addEventListener("touchmove", function (evt) {
+    let touch = evt.changedTouches[0];
+    let deltaX = touch.pageX - initX;
+    let deltaY = touch.pageY - initY;
+    div.style.transform = "translate(" + deltaX + "px, " + deltaY + "px)";
+    updatePreviousEvent(evt);
+  }, true);
+
+  div.addEventListener("touchend", function (evt) {
+    if (!evt.touches.length) {
+      div.style.transform = "none";
+    }
+    touchendTime = performance.now();
+    updatePreviousEvent(evt);
+  }, true);
+
+  div.addEventListener("mouseenter", function (evt) {
+    div.style.backgroundColor = "red";
+    updatePreviousEvent(evt);
+  }, true);
+  div.addEventListener("mouseover", function(evt) {
+    div.style.backgroundColor = "red";
+    updatePreviousEvent(evt);
+  }, true);
+
+  div.addEventListener("mouseout", function (evt) {
+    div.style.backgroundColor = "blue";
+    updatePreviousEvent(evt);
+  }, true);
+
+  div.addEventListener("mouseleave", function (evt) {
+    div.style.backgroundColor = "blue";
+    updatePreviousEvent(evt);
+  }, true);
+
+  div.addEventListener("mousedown", function (evt) {
+    if (previousEvent === "touchend" && touchendTime !== 0) {
+      let now = performance.now();
+      div.dataset.isDelay = ((now - touchendTime) >= 300);
+    } else {
+      div.dataset.isDelay = false;
+    }
+    updatePreviousEvent(evt);
+  }, true);
+
+  div.addEventListener("mousemove", updatePreviousEvent, true);
+
+  div.addEventListener("mouseup", updatePreviousEvent, true);
+
+  div.addEventListener("click", updatePreviousEvent, true);
+</script>
--- a/devtools/server/actors/pretty-print-worker.js
+++ b/devtools/server/actors/pretty-print-worker.js
@@ -23,17 +23,17 @@
  * pretty printed code back to the ugly source text.
  *
  * In the case of an error, the worker responds with a message of the form:
  *
  *     { id, error }
  */
 
 importScripts("resource://devtools/shared/worker/helper.js");
-importScripts("resource://devtools/acorn/acorn.js");
+importScripts("resource://devtools/shared/acorn/acorn.js");
 importScripts("resource://devtools/shared/sourcemap/source-map.js");
 importScripts("resource://devtools/shared/pretty-fast/pretty-fast.js");
 
 workerHelper.createTask(self, "pretty-print", ({ url, indent, source }) => {
   try {
     const prettified = prettyFast(source, {
       url: url,
       indent: " ".repeat(indent)
--- a/devtools/shared/Loader.jsm
+++ b/devtools/shared/Loader.jsm
@@ -39,19 +39,19 @@ BuiltinProvider.prototype = {
       // loader will map to the content subdirectory.  See the
       // README.md in devtools/shared/platform.
       "devtools/shared/platform": "resource://devtools/shared/platform/chrome",
       // ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
       "devtools": "resource://devtools",
       // ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
       "gcli": "resource://devtools/shared/gcli/source/lib/gcli",
       // ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
-      "acorn": "resource://devtools/acorn",
+      "acorn": "resource://devtools/shared/acorn",
       // ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
-      "acorn/util/walk": "resource://devtools/acorn/walk.js",
+      "acorn/util/walk": "resource://devtools/shared/acorn/walk.js",
       // ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
       "source-map": "resource://devtools/shared/sourcemap/source-map.js",
       // ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
       // Allow access to xpcshell test items from the loader.
       "xpcshell-test": "resource://test",
     };
     // When creating a Loader invisible to the Debugger, we have to ensure
     // using only modules and not depend on any JSM. As everything that is
--- a/devtools/shared/acorn/moz.build
+++ b/devtools/shared/acorn/moz.build
@@ -1,13 +1,13 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
 
-FINAL_TARGET_FILES.chrome.devtools.modules.devtools.acorn += [
+DevToolsModules(
     'acorn.js',
     'acorn_loose.js',
     'walk.js',
-]
+)
--- a/gfx/skia/skia/include/core/SkTypes.h
+++ b/gfx/skia/skia/include/core/SkTypes.h
@@ -4,16 +4,29 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
 
 #ifndef SkTypes_DEFINED
 #define SkTypes_DEFINED
 
 // IWYU pragma: begin_exports
+
+// In at least two known scenarios when using GCC with libc++:
+//  * GCC 4.8 targeting ARMv7 with NEON
+//  * GCC 4.9 targeting ARMv8 64 bit
+// we need to typedef float float32_t (or include <arm_neon.h> which does that)
+// before #including <memory>. This makes no sense.  I'm not very interested in
+// understanding why... these are old, bizarre platform configuration that we
+// should just let die.
+#if defined(MOZ_B2G) && defined(__GNUC__) && __GNUC__ == 4
+    typedef float float32_t;
+    #include <memory>
+#endif
+
 #include "SkPreConfig.h"
 #include "SkUserConfig.h"
 #include "SkPostConfig.h"
 #include <stddef.h>
 #include <stdint.h>
 
 #if defined(SK_ARM_HAS_NEON)
     #include <arm_neon.h>
--- a/old-configure.in
+++ b/old-configure.in
@@ -2487,17 +2487,17 @@ AC_SUBST(MOZ_B2G_VERSION)
 dnl ========================================================
 dnl Ensure Android SDK and build-tools versions depending on
 dnl mobile target.
 dnl ========================================================
 
 if test -z "$gonkdir" ; then
     case "$MOZ_BUILD_APP" in
     mobile/android)
-        MOZ_ANDROID_SDK(23, 23.0.3)
+        MOZ_ANDROID_SDK(23, 23.0.3 23.0.1)
         ;;
     esac
 fi
 
 dnl ========================================================
 dnl =
 dnl = Toolkit Options
 dnl =
--- a/security/manager/locales/en-US/chrome/pippki/deviceManager.dtd
+++ b/security/manager/locales/en-US/chrome/pippki/deviceManager.dtd
@@ -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/. -->
 
 <!ENTITY devmgr.title                           "Device Manager">
-<!-- LOCALIZATION NOTE (devmgr.style): This is CSS style for Device Manager
+<!-- LOCALIZATION NOTE (devmgr.style2): This is CSS style for Device Manager
      window size. Don't translate "width" nor "height". Adjust the numbers
      to make window contents fit. -->
-<!ENTITY devmgr.style                           "width: 52em; height: 32em;">
+<!ENTITY devmgr.style2                          "width: 67em; height: 32em;">
 
 <!ENTITY devmgr.devlist.label                   "Security Modules and Devices">
 <!ENTITY devmgr.details.title                   "Details">
 <!ENTITY devmgr.details.title2                  "Value">
 
 <!ENTITY devmgr.button.login.label              "Log In">
 <!ENTITY devmgr.button.login.accesskey          "n">
 <!ENTITY devmgr.button.logout.label             "Log Out">
--- a/security/manager/pki/resources/content/device_manager.xul
+++ b/security/manager/pki/resources/content/device_manager.xul
@@ -9,81 +9,81 @@
 <!ENTITY % deviceManangerDTD SYSTEM "chrome://pippki/locale/deviceManager.dtd">
 %deviceManangerDTD;
 <!ENTITY % pippkiDTD SYSTEM "chrome://pippki/locale/pippki.dtd" >
 %pippkiDTD;
 ]>
 
 <dialog id="devicemanager"
 	windowtype="mozilla:devicemanager"
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         title="&devmgr.title;"
-        style="&devmgr.style;"
+        style="&devmgr.style2;"
         persist="screenX screenY width height"
         onload="LoadModules();"
         onunload="DeregisterSmartCardObservers();"
         buttons="accept">
 
 <stringbundleset id="stringbundleset">
   <stringbundle id="pippki_bundle" src="chrome://pippki/locale/pippki.properties"/>
   <stringbundle id="pipnss_bundle" src="chrome://pipnss/locale/pipnss.properties"/>
 </stringbundleset>
 
 <script type="application/javascript" src="chrome://pippki/content/device_manager.js"/>
 
 <grid flex="1" style="margin:5px">
   <columns>
-    <column flex="1"/> 
-    <column flex="3"/> 
+    <column flex="1"/>
+    <column flex="3"/>
     <column/>
   </columns>
   <rows>
     <row flex="1">
       <vbox> <!-- List of devices -->
         <tree id="device_tree" seltype="single"
               onselect="enableButtons();" hidecolumnpicker="true"
               flex="1" style="min-width: 15em">
-          <treecols> 
+          <treecols>
             <treecol id="deviceCol" flex="1" primary="true" label="&devmgr.devlist.label;"/>
           </treecols>
           <treechildren id="device_list"/>
         </tree>
       </vbox> <!-- / List of devices -->
       <vbox> <!-- Device status -->
         <tree id="info_tree" seltype="single" hidecolumnpicker="true"
               flex="1" style="min-width: 10em">
-          <treecols> 
-            <treecol id="title1Col" flex="5" primary="true" label="&devmgr.details.title;"/> 
-            <treecol id="title2Col" flex="7" label="&devmgr.details.title2;"/> 
+          <treecols>
+            <treecol id="title1Col" flex="5" primary="true" label="&devmgr.details.title;"/>
+            <treecol id="title2Col" flex="7" label="&devmgr.details.title2;"/>
           </treecols>
           <treechildren id="info_list"/>
         </tree>
       </vbox> <!-- / Device status -->
       <vbox> <!-- Buttons for manipulating devices -->
-        <button id="login_button" 
+        <button id="login_button"
                 label="&devmgr.button.login.label;"
                 accesskey="&devmgr.button.login.accesskey;"
-                oncommand="doLogin();" disabled="true"/> 
-        <button id="logout_button" 
+                oncommand="doLogin();" disabled="true"/>
+        <button id="logout_button"
                 label="&devmgr.button.logout.label;"
                 accesskey="&devmgr.button.logout.accesskey;"
-                oncommand="doLogout();" disabled="true"/> 
-        <button id="change_pw_button" 
+                oncommand="doLogout();" disabled="true"/>
+        <button id="change_pw_button"
                 label="&devmgr.button.changepw.label;"
                 accesskey="&devmgr.button.changepw.accesskey;"
-                oncommand="changePassword();" disabled="true"/> 
-        <button id="load_button" 
+                oncommand="changePassword();" disabled="true"/>
+        <button id="load_button"
                 label="&devmgr.button.load.label;"
                 accesskey="&devmgr.button.load.accesskey;"
-                oncommand="doLoad();"/> 
-        <button id="unload_button" 
+                oncommand="doLoad();"/>
+        <button id="unload_button"
                 label="&devmgr.button.unload.label;"
                 accesskey="&devmgr.button.unload.accesskey;"
-                oncommand="doUnload();" disabled="true"/> 
-        <button id="fipsbutton" 
+                oncommand="doUnload();" disabled="true"/>
+        <button id="fipsbutton"
                 label=""
                 accesskey="&devmgr.button.fips.accesskey;"
                 oncommand="toggleFIPS();"/>
       </vbox> <!-- / Buttons for manipulating devices -->
     </row>
   </rows>
 </grid>
 
--- a/services/sync/moz.build
+++ b/services/sync/moz.build
@@ -41,17 +41,17 @@ EXTRA_JS_MODULES['services-sync'] += [
     'modules/util.js',
 ]
 
 EXTRA_PP_JS_MODULES['services-sync'] += [
     'modules/constants.js',
 ]
 
 # Definitions used by constants.js
-DEFINES['weave_version'] = '1.53.0'
+DEFINES['weave_version'] = '1.54.0'
 DEFINES['weave_id'] = '{340c2bbc-ce74-4362-90b5-7c26312808ef}'
 
 EXTRA_JS_MODULES['services-sync'].engines += [
     'modules/engines/addons.js',
     'modules/engines/bookmarks.js',
     'modules/engines/clients.js',
     'modules/engines/forms.js',
     'modules/engines/history.js',
--- a/toolkit/components/passwordmgr/nsILoginManagerPrompter.idl
+++ b/toolkit/components/passwordmgr/nsILoginManagerPrompter.idl
@@ -10,21 +10,25 @@ interface nsIDOMElement;
 interface nsIDOMWindow;
 
 [scriptable, uuid(425f73b9-b2db-4e8a-88c5-9ac2512934ce)]
 interface nsILoginManagerPrompter : nsISupports {
   /**
    * Initialize the prompter. Must be called before using other interfaces.
    *
    * @param aWindow
-   *        The in which the user is doing some login-related action that's
+   *        The window in which the user is doing some login-related action that's
    *        resulting in a need to prompt them for something. The prompt
    *        will be associated with this window (or, if a notification bar
    *        is being used, topmost opener in some cases).
    *
+   *        aWindow can be null if there is no associated window, e.g. in a JSM
+   *        or Sandbox. In this case there will be no checkbox to save the login
+   *        since the window is needed to know if this is a private context.
+   *
    *        If this window is a content window, the corresponding window and browser
    *        elements will be calculated. If this window is a chrome window, the
    *        corresponding browser element needs to be set using setBrowser.
    */
   void init(in nsIDOMWindow aWindow);
 
   /**
    * The browser this prompter is being created for.
--- a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
+++ b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
@@ -264,16 +264,17 @@ LoginManagerPrompter.prototype = {
     if (this._chromeWindow) {
       return PrivateBrowsingUtils.isWindowPrivate(this._chromeWindow);
     }
     // If we don't that we're in private browsing mode if the caller did
     // not provide a window.  The callers which really care about this
     // will indeed pass down a window to us, and for those who don't,
     // we can just assume that we don't want to save the entered login
     // information.
+    this.log("We have no chromeWindow so assume we're in a private context");
     return true;
   },
 
 
 
 
   /* ---------- nsIAuthPrompt prompts ---------- */
 
@@ -687,18 +688,22 @@ LoginManagerPrompter.prototype = {
   },
 
 
 
 
   /* ---------- nsILoginManagerPrompter prompts ---------- */
 
 
-  init : function (aWindow, aFactory) {
-    if (aWindow instanceof Ci.nsIDOMChromeWindow) {
+  init : function (aWindow = null, aFactory = null) {
+    if (!aWindow) {
+      // There may be no applicable window e.g. in a Sandbox or JSM.
+      this._chromeWindow = null;
+      this._browser = null;
+    } else if (aWindow instanceof Ci.nsIDOMChromeWindow) {
       this._chromeWindow = aWindow;
       // needs to be set explicitly using setBrowser
       this._browser = null;
     } else {
       let {win, browser} = this._getChromeWindow(aWindow);
       this._chromeWindow = win;
       this._browser = browser;
     }
--- a/toolkit/components/passwordmgr/test/mochitest/mochitest.ini
+++ b/toolkit/components/passwordmgr/test/mochitest/mochitest.ini
@@ -44,14 +44,16 @@ skip-if = toolkit == 'android' # autocom
 [test_input_events.html]
 [test_input_events_for_identical_values.html]
 [test_maxlength.html]
 [test_passwords_in_type_password.html]
 [test_prompt.html]
 skip-if = os == "linux" || toolkit == 'android' # Tests desktop prompts
 [test_prompt_http.html]
 skip-if = os == "linux" || toolkit == 'android' # Tests desktop prompts
+[test_prompt_noWindow.html]
+skip-if = e10s || toolkit == 'android' # Tests desktop prompts. e10s: bug 1217876
 [test_prompt_promptAuth.html]
 skip-if = os == "linux" || toolkit == 'android' # Tests desktop prompts
 [test_prompt_promptAuth_proxy.html]
 skip-if = e10s || os == "linux" || toolkit == 'android' # Tests desktop prompts
 [test_recipe_login_fields.html]
 [test_xhr_2.html]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/mochitest/test_prompt_noWindow.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test HTTP auth prompts by loading authenticate.sjs with no window</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="pwmgr_common.js"></script>
+  <script type="text/javascript" src="prompt_common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+
+<div id="content" style="display: none">
+</div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// Force parent to not look for tab-modal prompts, as they're not used for auth prompts.
+isTabModal = false;
+
+let chromeScript = runInParent(SimpleTest.getTestFileURL("pwmgr_common.js"));
+
+runInParent(() => {
+  const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+  Cu.import("resource://gre/modules/Services.jsm");
+
+  let login = Cc["@mozilla.org/login-manager/loginInfo;1"].
+              createInstance(Ci.nsILoginInfo);
+  login.init("http://mochi.test:8888", null, "mochitest",
+             "mochiuser1", "mochipass1", "", "");
+  Services.logins.addLogin(login);
+});
+
+add_task(function* test_sandbox_xhr() {
+  let state = {
+    msg         : "http://mochi.test:8888 is requesting your username and password. The site says: “mochitest”",
+    title       : "Authentication Required",
+    textValue   : "mochiuser1",
+    passValue   : "mochipass1",
+    iconClass   : "authentication-icon question-icon",
+    titleHidden : true,
+    textHidden  : false,
+    passHidden  : false,
+    checkHidden : true,
+    checkMsg    : "",
+    checked     : false,
+    focused     : "textField",
+    defButton   : "button0",
+  };
+  let action = {
+    buttonClick : "ok",
+  };
+  let promptDone = handlePrompt(state, action);
+
+  let url = new URL("authenticate.sjs?user=mochiuser1&pass=mochipass1", window.location.href);
+  let sandboxConstructor = SpecialPowers.Cu.Sandbox;
+  let sandbox = new sandboxConstructor(this, {wantXrays: true});
+  function sandboxedRequest(url) {
+    let req = SpecialPowers.Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+                           .createInstance(SpecialPowers.Ci.nsIXMLHttpRequest);
+    req.open("GET", url, true);
+    req.send(null);
+  }
+
+  let loginModifiedPromise = promiseStorageChanged(["modifyLogin"]);
+  sandbox.sandboxedRequest = sandboxedRequest(url);
+  info("send the XHR request in the sandbox");
+  SpecialPowers.Cu.evalInSandbox("sandboxedRequest;", sandbox);
+
+  yield promptDone;
+  info("prompt shown, waiting for metadata updates");
+  // Ensure the timeLastUsed and timesUsed metadata are updated.
+  yield loginModifiedPromise;
+});
+</script>
+</pre>
+</body>
+</html>
--- a/toolkit/content/tests/chrome/findbar_window.xul
+++ b/toolkit/content/tests/chrome/findbar_window.xul
@@ -147,16 +147,17 @@
       yield openFindbar();
       yield testFailedStringReset();
       gFindBar.close();
       yield testQuickFindClose();
       // TODO: This doesn't seem to work when the findbar is connected to a
       //       remote browser element.
       if (!gBrowser.hasAttribute("remote"))
         yield testFindAgainNotFound();
+      yield testToggleEntireWord();
     }
 
     function* testFindbarSelection() {
       function checkFindbarState(aTestName, aExpSelection) {
         ok(!gFindBar.hidden, "testFindbarSelection: failed to open findbar: " + aTestName);
         ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField,
            "testFindbarSelection: find field is not focused: " + aTestName);
         if (!gHasFindClipboard) {
@@ -230,19 +231,19 @@
         };
         setTimeout(_delayedCheckStatusText, 100);
       });
     }
 
     function promiseFindResult() {
       return new Promise(resolve => {
         let listener = {
-          onFindResult: function() {
+          onFindResult: function(result) {
             gFindBar.browser.finder.removeResultListener(listener);
-            resolve();
+            resolve(result);
           }
         };
         gFindBar.browser.finder.addResultListener(listener);
       });
     }
 
     function promiseMatchesCountResult() {
       return new Promise(resolve => {
@@ -645,16 +646,34 @@
       yield enterStringIntoFindField(SEARCH_TEXT);
       gFindBar.close();
       ok(gFindBar.hidden, "The findbar is closed.");
       promise = promiseFindResult();
       gFindBar.onFindAgainCommand();
       yield promise;
       ok(gFindBar.hidden, "Successful Find Again leaves the find bar closed.");
     }
+
+    function* testToggleEntireWord() {
+      yield openFindbar();
+      let promise = promiseFindResult();
+      yield enterStringIntoFindField("Tex", false);
+      let result = yield promise;
+      is(result.result, Ci.nsITypeAheadFind.FIND_FOUND, "Text should be found");
+
+      yield new Promise(resolve => setTimeout(resolve, ITERATOR_TIMEOUT));
+      promise = promiseFindResult();
+      let check = gFindBar.getElement("find-entire-word");
+      check.click();
+      result = yield promise;
+      is(result.result, Ci.nsITypeAheadFind.FIND_NOTFOUND, "Text should NOT be found");
+
+      check.click();
+      gFindBar.close(true);
+    }
   ]]></script>
 
   <commandset>
     <command id="cmd_find" oncommand="document.getElementById('FindToolbar').onFindCommand();"/>
   </commandset>
   <browser type="content-primary" flex="1" id="content" src="about:blank"/>
   <browser type="content-primary" flex="1" id="content-remote" remote="true" src="about:blank"/>
   <findbar id="FindToolbar" browserid="content"/>
--- a/toolkit/content/widgets/findbar.xml
+++ b/toolkit/content/widgets/findbar.xml
@@ -194,17 +194,17 @@
                          oncommand="_setCaseSensitivity(this.checked ? 1 : 0);"
                          type="checkbox"
                          xbl:inherits="accesskey=matchcaseaccesskey"/>
       <xul:toolbarbutton anonid="find-entire-word"
                          class="findbar-entire-word findbar-button tabbable"
                          label="&entireWord.label;"
                          accesskey="&entireWord.accesskey;"
                          tooltiptext="&entireWord.tooltiptext;"
-                         oncommand="_setEntireWord(this.checked);"
+                         oncommand="toggleEntireWord(this.checked);"
                          type="checkbox"
                          xbl:inherits="accesskey=entirewordaccesskey"/>
       <xul:label anonid="match-case-status" class="findbar-find-fast"/>
       <xul:label anonid="entire-word-status" class="findbar-find-fast"/>
       <xul:label anonid="found-matches" class="findbar-find-fast found-matches" hidden="true"/>
       <xul:image anonid="find-status-icon" class="findbar-find-fast find-status-icon"/>
       <xul:description anonid="find-status"
                        control="findbar-textbox"
@@ -338,19 +338,17 @@
             case "accessibility.typeaheadfind.linksonly":
               this._self._typeAheadLinksOnly = prefsvc.getBoolPref(aPrefName);
               break;
             case "accessibility.typeaheadfind.casesensitive":
               this._self._setCaseSensitivity(prefsvc.getIntPref(aPrefName));
               break;
             case "findbar.entireword":
               this._self._entireWord = prefsvc.getBoolPref(aPrefName);
-              this._self._updateEntireWord();
-              // Update the matches count.
-              this._updateMatchesCount(this.nsITypeAheadFind.FIND_FOUND);
+              this._self.toggleEntireWord(this._self._entireWord, true);
               break;
             case "findbar.highlightAll":
               this._self.toggleHighlight(prefsvc.getBoolPref(aPrefName), true);
               break;
             case "findbar.modalHighlight":
               this._self._useModalHighlight = prefsvc.getBoolPref(aPrefName);
               if (this._self.browser.finder)
                 this._self.browser.finder.onModalHighlightChange(this._self._useModalHighlight);
@@ -633,17 +631,17 @@
 
           this._dispatchFindEvent("casesensitivitychange");
         ]]></body>
       </method>
 
       <!--
         - Updates the entire-word mode of the findbar and its UI.
         -->
-      <method name="_updateEntireWord">
+      <method name="_setEntireWord">
         <body><![CDATA[
           let entireWord = this._entireWord;
           let checkbox = this.getElement("find-entire-word");
           let statusLabel = this.getElement("entire-word-status");
           checkbox.checked = entireWord;
 
           statusLabel.value = entireWord ? this._entireWordStr : "";
 
@@ -657,27 +655,28 @@
         ]]></body>
       </method>
 
       <!--
         - Sets the findbar entire-word mode
         - @param aEntireWord (boolean)
         - Whether or not entire-word mode should be turned on.
         -->
-      <method name="_setEntireWord">
+      <method name="toggleEntireWord">
         <parameter name="aEntireWord"/>
+        <parameter name="aFromPrefObserver"/>
         <body><![CDATA[
-          let prefsvc =
-            Components.classes["@mozilla.org/preferences-service;1"]
-                      .getService(Components.interfaces.nsIPrefBranch);
+          if (!aFromPrefObserver) {
+            // Just set the pref; our observer will change the find bar behavior.
+            this._prefsvc.setBoolPref("findbar.entireword", aEntireWord);
+            return;
+          }
 
-          // Just set the pref; our observer will change the find bar behavior.
-          prefsvc.setBoolPref("findbar.entireword", aEntireWord);
-
-          this._maybeHighlightAll();
+          this._findFailedString = null;
+          this._find();
         ]]></body>
       </method>
 
       <field name="_strBundle">null</field>
       <property name="strBundle">
         <getter><![CDATA[
           if (!this._strBundle) {
             this._strBundle =
@@ -966,17 +965,17 @@
             if (node == wrapper || node == foundMatches)
                continue;
             node.hidden = showMinimalUI;
           }
           this.getElement("find-next").hidden =
             this.getElement("find-previous").hidden = showMinimalUI;
           foundMatches.hidden = showMinimalUI || !foundMatches.value;
           this._updateCaseSensitivity();
-          this._updateEntireWord();
+          this._setEntireWord();
           this._setHighlightAll();
 
           if (showMinimalUI)
             this._findField.classList.add("minimal");
           else
             this._findField.classList.remove("minimal");
 
           if (this._findMode == this.FIND_TYPEAHEAD)
@@ -1014,17 +1013,17 @@
             // initial prefilling is ignored if it hasn't happened yet.
             if (this._startFindDeferred) {
               this._startFindDeferred.resolve();
               this._startFindDeferred = null;
             }
 
             this._enableFindButtons(val);
             this._updateCaseSensitivity(val);
-            this._updateEntireWord();
+            this._setEntireWord();
 
             this.browser.finder.fastFind(val, this._findMode == this.FIND_LINKS,
                                          this._findMode != this.FIND_NORMAL);
           }
 
           if (this._findMode != this.FIND_NORMAL)
             this._setFindCloseTimeout();
 
--- a/toolkit/modules/FinderHighlighter.jsm
+++ b/toolkit/modules/FinderHighlighter.jsm
@@ -401,18 +401,17 @@ FinderHighlighter.prototype = {
         if (this.iterator._areParamsEqual(params, dict.lastIteratorParams))
           return;
         if (params)
           this.highlight(true, params.word, params.linksOnly);
       }
       return;
     }
 
-    // Place the match placeholder on top of the current found range.
-    if (data.result == Ci.nsITypeAheadFind.FIND_NOTFOUND || !foundRange) {
+    if (data.result == Ci.nsITypeAheadFind.FIND_NOTFOUND || !data.searchString || !foundRange) {
       this.hide();
       return;
     }
 
     if (foundRange !== dict.currentFoundRange || data.findAgain) {
       dict.currentFoundRange = foundRange;
 
       let textContent = this._getRangeContentArray(foundRange);
@@ -441,17 +440,17 @@ FinderHighlighter.prototype = {
     if (outlineNode) {
       if (dict.animation)
         dict.animation.finish();
       dict.animation = outlineNode.setAnimationForElement(kModalOutlineId,
         Cu.cloneInto(kModalOutlineAnim.keyframes, window), kModalOutlineAnim.duration);
       dict.animation.onfinish = () => dict.animation = null;
     }
 
-    if (this._highlightAll && data.searchString)
+    if (this._highlightAll)
       this.highlight(true, data.searchString, data.linksOnly);
   },
 
   /**
    * Invalidates the list by clearing the map of highlighted ranges that we
    * keep to build the mask for.
    */
   clear(window = null) {
--- a/toolkit/modules/tests/browser/browser_FinderHighlighter.js
+++ b/toolkit/modules/tests/browser/browser_FinderHighlighter.js
@@ -385,8 +385,37 @@ add_task(function* testHideOnLocationCha
     insertCalls: [0, 0],
     removeCalls: [1, 2]
   });
   yield BrowserTestUtils.loadURI(browser, url);
   yield promise;
 
   yield BrowserTestUtils.removeTab(tab);
 });
+
+add_task(function* testHideOnClear() {
+  let url = kFixtureBaseURL + "file_FinderSample.html";
+  yield BrowserTestUtils.withNewTab(url, function* (browser) {
+    let findbar = gBrowser.getFindBar();
+    yield promiseOpenFindbar(findbar);
+
+    let word = "Roland";
+    let expectedResult = {
+      rectCount: 1,
+      insertCalls: [2, 4],
+      removeCalls: [1, 2]
+    };
+    let promise = promiseTestHighlighterOutput(browser, word, expectedResult);
+    yield promiseEnterStringIntoFindField(findbar, word);
+    yield promise;
+
+    yield new Promise(resolve => setTimeout(resolve, kIteratorTimeout));
+    promise = promiseTestHighlighterOutput(browser, "", {
+      rectCount: 0,
+      insertCalls: [0, 0],
+      removeCalls: [1, 2]
+    });
+    findbar.clear();
+    yield promise;
+
+    findbar.close(true);
+  });
+});
--- a/xpcom/components/Module.h
+++ b/xpcom/components/Module.h
@@ -17,17 +17,17 @@ namespace mozilla {
 /**
  * A module implements one or more XPCOM components. This structure is used
  * for both binary and script modules, but the registration members
  * (cids/contractids/categoryentries) are unused for modules which are loaded
  * via a module loader.
  */
 struct Module
 {
-  static const unsigned int kVersion = 51;
+  static const unsigned int kVersion = 52;
 
   struct CIDEntry;
 
   typedef already_AddRefed<nsIFactory> (*GetFactoryProcPtr)(
     const Module& module, const CIDEntry& entry);
 
   typedef nsresult (*ConstructorProcPtr)(nsISupports* aOuter,
                                          const nsIID& aIID,