merge fx-team to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 19 Mar 2015 14:00:57 +0100
changeset 234403 cbd0efcd976c6fa677637d565d948296684441de
parent 234392 0a11b73c77b78b08ea55b05e368a6522a34fa251 (current diff)
parent 234402 bb305274f26238e667a18333449126b80292d1be (diff)
child 234416 ea4ac9b3df2bd8ba6f29fcf88b1fcf74c7be60f7
child 234468 661d70e3289993ed2f6477cd5847ab99d9998177
child 234538 78651150328222d05146b55d56a5ea18858b8b6a
push id28444
push usercbook@mozilla.com
push dateThu, 19 Mar 2015 13:02:09 +0000
treeherdermozilla-central@cbd0efcd976c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge fx-team to mozilla-central a=merge
browser/themes/shared/readinglist/sidebar.css
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -2997,17 +2997,17 @@
         ]]></setter>
       </property>
       <property name="_notificationType">
         <getter><![CDATA[
           // Use the popupid attribute to identify the notification type,
           // otherwise just rely on the panel id for common arrowpanels.
           let type = this._panel.firstChild.getAttribute("popupid") ||
                      this._panel.id;
-          if (type.startsWith("password-"))
+          if (type == "password")
             return "passwords";
           if (type == "editBookmarkPanel")
             return "bookmarks";
           if (type == "addon-install-complete") {
             if (!Services.prefs.prefHasUserValue("services.sync.username"))
               return "addons";
             if (!Services.prefs.getBoolPref("services.sync.engine.addons"))
               return "addons-sync-disabled";
--- a/browser/components/readinglist/sidebar.js
+++ b/browser/components/readinglist/sidebar.js
@@ -49,16 +49,17 @@ let RLSidebar = {
    * Initialize the sidebar UI.
    */
   init() {
     log.debug("Initializing");
 
     addEventListener("unload", () => this.uninit());
 
     this.list = document.getElementById("list");
+    this.emptyListInfo = document.getElementById("emptyListInfo");
     this.itemTemplate = document.getElementById("item-template");
 
     this.list.addEventListener("click", event => this.onListClick(event));
     this.list.addEventListener("mousemove", event => this.onListMouseMove(event));
     this.list.addEventListener("keydown", event => this.onListKeyDown(event), true);
 
     this.listPromise = this.ensureListItems();
     ReadingList.addListener(this);
@@ -86,31 +87,35 @@ let RLSidebar = {
   onItemAdded(item) {
     log.trace(`onItemAdded: ${item}`);
 
     let itemNode = document.importNode(this.itemTemplate.content, true).firstElementChild;
     this.updateItem(item, itemNode);
     this.list.appendChild(itemNode);
     this.itemNodesById.set(item.id, itemNode);
     this.itemsById.set(item.id, item);
+
+    this.emptyListInfo.hidden = true;
   },
 
   /**
    * Handle an item being deleted from the ReadingList.
    * @param {ReadingListItem} item - Item that was deleted.
    */
   onItemDeleted(item) {
     log.trace(`onItemDeleted: ${item}`);
 
     let itemNode = this.itemNodesById.get(item.id);
     itemNode.remove();
     this.itemNodesById.delete(item.id);
     this.itemsById.delete(item.id);
     // TODO: ensureListItems doesn't yet cope with needing to add one item.
     //this.ensureListItems();
+
+    this.emptyListInfo.hidden = (this.numItems > 0);
   },
 
   /**
    * Handle an item in the ReadingList having any of its properties changed.
    * @param {ReadingListItem} item - Item that was updated.
    */
   onItemUpdated(item) {
     log.trace(`onItemUpdated: ${item}`);
@@ -143,16 +148,17 @@ let RLSidebar = {
     yield ReadingList.forEachItem(item => {
       // TODO: Should be batch inserting via DocumentFragment
       try {
         this.onItemAdded(item);
       } catch (e) {
         log.warn("Error adding item", e);
       }
     });
+    this.emptyListInfo.hidden = (this.numItems > 0);
   }),
 
   /**
    * Get the number of items currently displayed in the list.
    * @type {number}
    */
   get numItems() {
     return this.list.childElementCount;
@@ -345,16 +351,21 @@ let RLSidebar = {
    * Handle a click event on the list box.
    * @param {Event} event - Triggering event.
    */
   onListClick(event) {
     let itemNode = this.findParentItemNode(event.target);
     if (!itemNode)
       return;
 
+    if (event.target.classList.contains("remove-button")) {
+      ReadingList.deleteItem(this.getItemFromNode(itemNode));
+      return;
+    }
+
     this.activeItem = itemNode;
     this.openActiveItem(event);
   },
 
   /**
    * Handle a mousemove event over the list box.
    * @param {Event} event - Triggering event.
    */
--- a/browser/components/readinglist/sidebar.xhtml
+++ b/browser/components/readinglist/sidebar.xhtml
@@ -6,25 +6,29 @@
 <!DOCTYPE html [
   <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
   %browserDTD;
 ]>
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
     <script src="chrome://browser/content/readinglist/sidebar.js" type="application/javascript;version=1.8"></script>
     <link rel="stylesheet" type="text/css" media="all" href="chrome://browser/skin/readinglist/sidebar.css"/>
-    <!-- <title>&readingList.label;</title> -->
+    <title>&readingList.label;</title>
   </head>
 
   <body role="application">
     <template id="item-template">
       <div class="item" role="option" tabindex="-1">
         <div class="item-thumb-container"></div>
         <div class="item-summary-container">
-          <div class="item-title"></div>
+          <div class="item-title-lines">
+            <p class="item-title"/>
+            <button class="remove-button" title="&readingList.sidebar.delete.tooltip;"/>
+          </div>
           <div class="item-domain"></div>
         </div>
       </div>
     </template>
 
+    <div id="emptyListInfo" hidden="true">&readingList.sidebar.emptyText;</div>
     <div id="list" role="listbox" tabindex="1"></div>
   </body>
 </html>
--- a/browser/devtools/webide/content/wifi-auth.js
+++ b/browser/devtools/webide/content/wifi-auth.js
@@ -4,18 +4,16 @@
 
 "use strict";
 
 const Cu = Components.utils;
 const { Services } = Cu.import("resource://gre/modules/Services.jsm");
 const { require } =
   Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
 const QR = require("devtools/toolkit/qrcode/index");
-const PROPERTIES = "chrome://browser/locale/devtools/webide.properties";
-const Strings = Services.strings.createBundle(PROPERTIES);
 
 window.addEventListener("load", function onLoad() {
   window.removeEventListener("load", onLoad);
   document.getElementById("close").onclick = () => window.close();
   document.getElementById("no-scanner").onclick = showToken;
   document.getElementById("yes-scanner").onclick = hideToken;
   buildUI();
 });
@@ -28,20 +26,16 @@ function buildUI() {
 
 function createQR(oob) {
   let oobData = JSON.stringify(oob);
   let imgData = QR.encodeToDataURI(oobData, "L" /* low quality */);
   document.querySelector("#qr-code img").src = imgData.src;
 }
 
 function createToken(oob) {
-  let spacedCert = oob.sha256.replace(/:/g, " ").toLowerCase();
-  let certText = Strings.formatStringFromName("wifi_auth_cert",
-                                              [spacedCert], 1);
-  document.querySelector("#cert").textContent = certText;
   let token = oob.sha256.replace(/:/g, "").toLowerCase() + oob.k;
   document.querySelector("#token pre").textContent = token;
 }
 
 function showToken() {
   document.querySelector("body").setAttribute("token", "true");
 }
 
--- a/browser/devtools/webide/content/wifi-auth.xhtml
+++ b/browser/devtools/webide/content/wifi-auth.xhtml
@@ -19,17 +19,16 @@
   <body>
 
     <div id="controls">
       <a id="close">&deck_close;</a>
     </div>
 
     <h3 id="header">&wifi_auth_header;</h3>
     <div id="scan-request">&wifi_auth_scan_request;</div>
-    <div id="cert"></div>
 
     <div id="qr-code">
       <div id="qr-code-wrapper">
         <img/>
       </div>
       <a id="no-scanner" class="toggle-scanner">&wifi_auth_no_scanner;</a>
     </div>
 
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -848,13 +848,12 @@ just addresses the organization to follo
 
 <!ENTITY readingList.label                        "Reading List">
 <!ENTITY readingList.sidebar.commandKey           "R">
 <!ENTITY readingList.showSidebar.label            "Show Reading List Sidebar">
 <!-- Pre-landed string for bug 1124153 -->
 <!ENTITY readingList.sidebar.showMore.label       "Show moreā€¦">
 <!-- Pre-landed string for bug 1133662 -->
 <!ENTITY readingList.sidebar.emptyText            "Add articles to your Reading List to save them for later and find them easily when you need them.">
-<!-- Pre-landed string for bug 1123525 -->
 <!ENTITY readingList.sidebar.delete.tooltip       "Remove this from your Reading List">
 <!-- Pre-landed strings for bug 1123519 -->
 <!ENTITY readingList.sidebar.add.label            "Add to Reading List">
 <!ENTITY readingList.sidebar.add.tooltip          "Add this page to your Reading List">
--- a/browser/locales/en-US/chrome/browser/devtools/webide.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/webide.properties
@@ -72,14 +72,8 @@ runtimedetails_notUSBDevice=Not a USB de
 status_tooltip=Validation status: %1$S
 status_valid=VALID
 status_warning=WARNINGS
 status_error=ERRORS
 status_unknown=UNKNOWN
 
 # Device preferences and settings
 device_reset_default=Reset to default
-
-# WiFi Auth
-# LOCALIZATION NOTE (wifi_auth_cert): Part of the dialog that instructs the
-# user to transfer an authentication token to the server.
-# %1$S: The client's cert fingerprint
-wifi_auth_cert=My Cert: %1$S
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1190,18 +1190,17 @@ toolbarbutton[sdk-button="true"][cui-are
 }
 
 .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
 .popup-notification-icon[popupid*="offline-app-requested"],
 .popup-notification-icon[popupid="offline-app-usage"] {
   list-style-image: url(chrome://global/skin/icons/question-64.png);
 }
 
-.popup-notification-icon[popupid="password-save"],
-.popup-notification-icon[popupid="password-change"] {
+.popup-notification-icon[popupid="password"] {
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
 }
 
 .popup-notification-icon[popupid="webapps-install-progress"],
 .popup-notification-icon[popupid="webapps-install"] {
   list-style-image: url(chrome://global/skin/icons/webapps-64.png);
 }
 
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -88,17 +88,17 @@ browser.jar:
   skin/classic/browser/undoCloseTab.png                        (../shared/undoCloseTab.png)
   skin/classic/browser/urlbar-arrow.png
   skin/classic/browser/session-restore.svg                  (../shared/incontent-icons/session-restore.svg)
   skin/classic/browser/tab-crashed.svg                      (../shared/incontent-icons/tab-crashed.svg)
   skin/classic/browser/welcome-back.svg                     (../shared/incontent-icons/welcome-back.svg)
   skin/classic/browser/reader-mode-16.png             (../shared/reader/reader-mode-16.png)
   skin/classic/browser/readinglist/icons.svg          (../shared/readinglist/icons.svg)
   skin/classic/browser/readinglist/readinglist-icon.svg (../shared/readinglist/readinglist-icon.svg)
-  skin/classic/browser/readinglist/sidebar.css        (../shared/readinglist/sidebar.css)
+* skin/classic/browser/readinglist/sidebar.css        (readinglist/sidebar.css)
   skin/classic/browser/webRTC-shareDevice-16.png
   skin/classic/browser/webRTC-shareDevice-64.png
   skin/classic/browser/webRTC-sharingDevice-16.png    (../shared/webrtc/webRTC-sharingDevice-16.png)
   skin/classic/browser/webRTC-shareMicrophone-16.png
   skin/classic/browser/webRTC-shareMicrophone-64.png
   skin/classic/browser/webRTC-sharingMicrophone-16.png (../shared/webrtc/webRTC-sharingMicrophone-16.png)
   skin/classic/browser/webRTC-shareScreen-16.png      (../shared/webrtc/webRTC-shareScreen-16.png)
   skin/classic/browser/webRTC-shareScreen-64.png      (../shared/webrtc/webRTC-shareScreen-64.png)
new file mode 100644
--- /dev/null
+++ b/browser/themes/linux/readinglist/sidebar.css
@@ -0,0 +1,29 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+%include ../../shared/readinglist/sidebar.inc.css
+
+.item {
+  -moz-padding-end: 0;
+}
+
+.item-title {
+  margin: 1px 0 0;
+}
+
+.item-title, .item-domain {
+  -moz-margin-end: 6px;
+}
+
+.remove-button {
+  background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 16, 16, 0);
+}
+
+.remove-button:hover {
+  background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 32, 16, 16);
+}
+
+.remove-button:hover:active {
+  background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 48, 16, 32);
+}
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -4215,18 +4215,17 @@ notification[value="loop-sharing-notific
 }
 
 .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
 .popup-notification-icon[popupid*="offline-app-requested"],
 .popup-notification-icon[popupid="offline-app-usage"] {
   list-style-image: url(chrome://global/skin/icons/question-64.png);
 }
 
-.popup-notification-icon[popupid="password-save"],
-.popup-notification-icon[popupid="password-change"] {
+.popup-notification-icon[popupid="password"] {
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
 }
 
 .popup-notification-icon[popupid="webapps-install-progress"],
 .popup-notification-icon[popupid="webapps-install"] {
   list-style-image: url(chrome://global/skin/icons/webapps-64.png);
 }
 
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -139,17 +139,17 @@ browser.jar:
   skin/classic/browser/urlbar-popup-blocked@2x.png
   skin/classic/browser/session-restore.svg            (../shared/incontent-icons/session-restore.svg)
   skin/classic/browser/tab-crashed.svg                (../shared/incontent-icons/tab-crashed.svg)
   skin/classic/browser/welcome-back.svg               (../shared/incontent-icons/welcome-back.svg)
   skin/classic/browser/reader-mode-16.png             (../shared/reader/reader-mode-16.png)
   skin/classic/browser/reader-mode-16@2x.png          (../shared/reader/reader-mode-16@2x.png)
   skin/classic/browser/readinglist/icons.svg          (../shared/readinglist/icons.svg)
   skin/classic/browser/readinglist/readinglist-icon.svg (../shared/readinglist/readinglist-icon.svg)
-  skin/classic/browser/readinglist/sidebar.css        (../shared/readinglist/sidebar.css)
+* skin/classic/browser/readinglist/sidebar.css        (readinglist/sidebar.css)
   skin/classic/browser/webRTC-shareDevice-16.png
   skin/classic/browser/webRTC-shareDevice-16@2x.png
   skin/classic/browser/webRTC-shareDevice-64.png
   skin/classic/browser/webRTC-shareDevice-64@2x.png
   skin/classic/browser/webRTC-sharingDevice-16.png    (../shared/webrtc/webRTC-sharingDevice-16.png)
   skin/classic/browser/webRTC-sharingDevice-16@2x.png (../shared/webrtc/webRTC-sharingDevice-16@2x.png)
   skin/classic/browser/webRTC-shareMicrophone-16.png
   skin/classic/browser/webRTC-shareMicrophone-16@2x.png
new file mode 100644
--- /dev/null
+++ b/browser/themes/osx/readinglist/sidebar.css
@@ -0,0 +1,35 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+%include ../../shared/readinglist/sidebar.inc.css
+
+.item-title {
+  margin: 4px 0 0;
+}
+
+.remove-button {
+  background-image: -moz-image-rect(url("chrome://global/skin/icons/close.png"), 0, 16, 16, 0);
+}
+
+.remove-button:hover {
+  background-image: -moz-image-rect(url("chrome://global/skin/icons/close.png"), 0, 32, 16, 16);
+}
+
+.remove-button:hover:active {
+  background-image: -moz-image-rect(url("chrome://global/skin/icons/close.png"), 0, 48, 16, 32);
+}
+
+@media (min-resolution: 2dppx) {
+  .remove-button {
+    background-image: -moz-image-rect(url("chrome://global/skin/icons/close@2x.png"), 0, 32, 32, 0);
+  }
+
+  .remove-button:hover {
+    background-image: -moz-image-rect(url("chrome://global/skin/icons/close@2x.png"), 0, 64, 32, 32);
+  }
+
+  .remove-button:hover:active {
+    background-image: -moz-image-rect(url("chrome://global/skin/icons/close@2x.png"), 0, 96, 32, 64);
+  }
+}
rename from browser/themes/shared/readinglist/sidebar.css
rename to browser/themes/shared/readinglist/sidebar.inc.css
--- a/browser/themes/shared/readinglist/sidebar.css
+++ b/browser/themes/shared/readinglist/sidebar.inc.css
@@ -1,26 +1,32 @@
-/* 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/.
 
 :root, body {
   height: 100%;
   overflow-x: hidden;
 }
 
 body {
   margin: 0;
   font: message-box;
   background: #F8F7F8;
   color: #333333;
   -moz-user-select: none;
   overflow: hidden;
 }
 
+#emptyListInfo {
+  cursor: default;
+  padding: 3em 1em;
+  text-align: center;
+}
+
 #list {
   height: 100%;
   overflow-x: auto;
 }
 
 .item {
   display: flex;
   flex-flow: row;
@@ -47,26 +53,46 @@ body {
   margin: 5px;
 }
 
 .item-summary-container {
   display: flex;
   flex-flow: column;
   -moz-padding-start: 4px;
   overflow: hidden;
+  flex-grow: 1;
+}
+
+.item-title-lines {
+  display: flex;
 }
 
 .item-title {
   overflow: hidden;
-  height: 2.8em;
+  max-height: 2.8em;
+  line-height: 1.4;
+  flex-grow: 1;
 }
 
 .item-domain {
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
   max-height: 1.4em;
   color: #0095DD;
 }
 
 .item:hover .item-domain {
   color: #008ACB;
 }
+
+.item:not(:hover) .remove-button {
+  display: none;
+}
+
+.remove-button {
+  width: 16px;
+  height: 16px;
+  background-size: contain;
+  background-color: transparent;
+  border-width: 0;
+}
+
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -2212,18 +2212,17 @@ toolbarbutton.bookmark-item[dragover="tr
 }
 
 .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
 .popup-notification-icon[popupid*="offline-app-requested"],
 .popup-notification-icon[popupid="offline-app-usage"] {
   list-style-image: url(chrome://global/skin/icons/question-64.png);
 }
 
-.popup-notification-icon[popupid="password-save"],
-.popup-notification-icon[popupid="password-change"] {
+.popup-notification-icon[popupid="password"] {
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
 }
 
 .popup-notification-icon[popupid="webapps-install-progress"],
 .popup-notification-icon[popupid="webapps-install"] {
   list-style-image: url(chrome://global/skin/icons/webapps-64.png);
 }
 
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -107,17 +107,17 @@ browser.jar:
         skin/classic/browser/urlbar-popup-blocked.png
         skin/classic/browser/urlbar-history-dropmarker.png
         skin/classic/browser/session-restore.svg                     (../shared/incontent-icons/session-restore.svg)
         skin/classic/browser/tab-crashed.svg                         (../shared/incontent-icons/tab-crashed.svg)
         skin/classic/browser/welcome-back.svg                        (../shared/incontent-icons/welcome-back.svg)
         skin/classic/browser/reader-mode-16.png                      (../shared/reader/reader-mode-16.png)
         skin/classic/browser/readinglist/icons.svg                   (../shared/readinglist/icons.svg)
         skin/classic/browser/readinglist/readinglist-icon.svg        (../shared/readinglist/readinglist-icon.svg)
-        skin/classic/browser/readinglist/sidebar.css                 (../shared/readinglist/sidebar.css)
+*       skin/classic/browser/readinglist/sidebar.css                 (readinglist/sidebar.css)
         skin/classic/browser/notification-pluginNormal.png           (../shared/plugins/notification-pluginNormal.png)
         skin/classic/browser/notification-pluginAlert.png            (../shared/plugins/notification-pluginAlert.png)
         skin/classic/browser/notification-pluginBlocked.png          (../shared/plugins/notification-pluginBlocked.png)
         skin/classic/browser/webRTC-shareDevice-16.png
         skin/classic/browser/webRTC-shareDevice-64.png
         skin/classic/browser/webRTC-sharingDevice-16.png             (../shared/webrtc/webRTC-sharingDevice-16.png)
         skin/classic/browser/webRTC-shareMicrophone-16.png
         skin/classic/browser/webRTC-shareMicrophone-64.png
@@ -579,17 +579,17 @@ browser.jar:
         skin/classic/aero/browser/urlbar-popup-blocked.png
         skin/classic/aero/browser/urlbar-history-dropmarker.png
         skin/classic/aero/browser/session-restore.svg               (../shared/incontent-icons/session-restore.svg)
         skin/classic/aero/browser/tab-crashed.svg                   (../shared/incontent-icons/tab-crashed.svg)
         skin/classic/aero/browser/welcome-back.svg                  (../shared/incontent-icons/welcome-back.svg)
         skin/classic/aero/browser/reader-mode-16.png                (../shared/reader/reader-mode-16.png)
         skin/classic/aero/browser/readinglist/icons.svg             (../shared/readinglist/icons.svg)
         skin/classic/aero/browser/readinglist/readinglist-icon.svg  (../shared/readinglist/readinglist-icon.svg)
-        skin/classic/aero/browser/readinglist/sidebar.css           (../shared/readinglist/sidebar.css)
+*       skin/classic/aero/browser/readinglist/sidebar.css           (readinglist/sidebar.css)
         skin/classic/aero/browser/notification-pluginNormal.png     (../shared/plugins/notification-pluginNormal.png)
         skin/classic/aero/browser/notification-pluginAlert.png      (../shared/plugins/notification-pluginAlert.png)
         skin/classic/aero/browser/notification-pluginBlocked.png    (../shared/plugins/notification-pluginBlocked.png)
         skin/classic/aero/browser/webRTC-shareDevice-16.png
         skin/classic/aero/browser/webRTC-shareDevice-64.png
         skin/classic/aero/browser/webRTC-sharingDevice-16.png             (../shared/webrtc/webRTC-sharingDevice-16.png)
         skin/classic/aero/browser/webRTC-shareMicrophone-16.png
         skin/classic/aero/browser/webRTC-shareMicrophone-64.png
new file mode 100644
--- /dev/null
+++ b/browser/themes/windows/readinglist/sidebar.css
@@ -0,0 +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/. */
+
+%include ../../shared/readinglist/sidebar.inc.css
+
+.item {
+  -moz-padding-end: 0;
+}
+
+.item-title {
+  margin: 1px 0 0;
+}
+
+.item-title, .item-domain {
+  -moz-margin-end: 6px;
+}
+
+.remove-button {
+  -moz-margin-end: 2px;
+  background-image: -moz-image-rect(url("chrome://global/skin/icons/close.png"), 0, 16, 16, 0);
+}
+
+.remove-button:hover {
+  background-image: -moz-image-rect(url("chrome://global/skin/icons/close.png"), 0, 32, 16, 16);
+}
+
+.remove-button:hover:active {
+  background-image: -moz-image-rect(url("chrome://global/skin/icons/close.png"), 0, 48, 16, 32);
+}
--- a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
+++ b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
@@ -849,20 +849,22 @@ LoginManagerPrompter.prototype = {
             pwmgr.setLoginSavingEnabled(aLogin.hostname, false);
             browser.focus();
           }
         }
       ];
 
       var { browser } = this._getNotifyWindow();
 
-      aNotifyObj.show(browser, "password-save", notificationText,
+      aNotifyObj.show(browser, "password", notificationText,
                       "password-notification-icon", mainAction,
-                      secondaryActions, { timeout: Date.now() + 10000,
-                                          persistWhileVisible: true });
+                      secondaryActions,
+                      { timeout: Date.now() + 10000,
+                        persistWhileVisible: true,
+                        passwordNotificationType: "password-save" });
     } else {
       var notNowButtonText =
             this._getLocalizedString("notifyBarNotNowButtonText");
       var notNowButtonAccessKey =
             this._getLocalizedString("notifyBarNotNowButtonAccessKey");
       var buttons = [
         // "Remember" button
         {
@@ -901,17 +903,17 @@ LoginManagerPrompter.prototype = {
 
   /*
    * _removeLoginNotifications
    *
    */
   _removeLoginNotifications : function () {
     var popupNote = this._getPopupNote();
     if (popupNote)
-      popupNote = popupNote.getNotification("password-save");
+      popupNote = popupNote.getNotification("password");
     if (popupNote)
       popupNote.remove();
 
     var notifyBox = this._getNotifyBox();
     if (notifyBox) {
       var oldBar = notifyBox.getNotificationWithValue("password-save");
       if (oldBar) {
         this.log("Removing save-password notification bar.");
@@ -1047,20 +1049,21 @@ LoginManagerPrompter.prototype = {
           self._updateLogin(aOldLogin, aNewPassword);
           promptHistogram.add(PROMPT_UPDATE);
         }
       };
 
       var { browser } = this._getNotifyWindow();
 
       Services.telemetry.getHistogramById("PWMGR_PROMPT_UPDATE_ACTION").add(PROMPT_DISPLAYED);
-      aNotifyObj.show(browser, "password-change", notificationText,
+      aNotifyObj.show(browser, "password", notificationText,
                       "password-notification-icon", mainAction,
                       null, { timeout: Date.now() + 10000,
-                              persistWhileVisible: true });
+                              persistWhileVisible: true,
+                              passwordNotificationType: "password-change" });
     } else {
       var dontChangeButtonText =
             this._getLocalizedString("notifyBarDontChangeButtonText");
       var dontChangeButtonAccessKey =
             this._getLocalizedString("notifyBarDontChangeButtonAccessKey");
       var buttons = [
         // "Yes" button
         {
--- a/toolkit/components/passwordmgr/test/browser/browser.ini
+++ b/toolkit/components/passwordmgr/test/browser/browser.ini
@@ -1,10 +1,12 @@
 [DEFAULT]
 support-files =
   authenticate.sjs
+  form_basic.html
 
+[browser_notifications.js]
 [browser_passwordmgr_fields.js]
 [browser_passwordmgr_observers.js]
 [browser_passwordmgr_sort.js]
 [browser_passwordmgr_switchtab.js]
 [browser_passwordmgrcopypwd.js]
 [browser_passwordmgrdlg.js]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/browser/browser_notifications.js
@@ -0,0 +1,33 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+add_task(function* test_save() {
+  let tab = gBrowser.addTab("https://example.com/browser/toolkit/components/" +
+                            "passwordmgr/test/browser/form_basic.html");
+  let browser = tab.linkedBrowser;
+  yield BrowserTestUtils.browserLoaded(browser);
+  gBrowser.selectedTab = tab;
+
+  let promiseShown = BrowserTestUtils.waitForEvent(PopupNotifications.panel,
+                                                   "Shown");
+  yield ContentTask.spawn(browser, null, function* () {
+    content.document.getElementById("form-basic-username").value = "username";
+    content.document.getElementById("form-basic-password").value = "password";
+    content.document.getElementById("form-basic").submit();
+  });
+  yield promiseShown;
+  let notificationElement = PopupNotifications.panel.childNodes[0];
+
+  let promiseLogin = TestUtils.topicObserved("passwordmgr-storage-changed",
+                                             (_, data) => data == "addLogin");
+  notificationElement.button.doCommand();
+  let [login] = yield promiseLogin;
+  login.QueryInterface(Ci.nsILoginInfo);
+
+  Assert.equal(login.username, "username");
+  Assert.equal(login.password, "password");
+
+  // Cleanup.
+  Services.logins.removeAllLogins();
+  gBrowser.removeTab(tab);
+});
new file mode 100644
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/browser/form_basic.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<!-- Simplest form with username and password fields. -->
+<form id="form-basic">
+  <input id="form-basic-username" name="username">
+  <input id="form-basic-password" name="password" type="password">
+  <input id="form-basic-submit" type="submit">
+</form>
+
+</body></html>
--- a/toolkit/components/passwordmgr/test/notification_common.js
+++ b/toolkit/components/passwordmgr/test/notification_common.js
@@ -34,17 +34,21 @@ function getPopupNotifications(aWindow) 
 
 
 /*
  * getPopup
  *
  */
 function getPopup(aPopupNote, aKind) {
     ok(true, "Looking for " + aKind + " popup notification");
-    return aPopupNote.getNotification(aKind);
+    var notification = aPopupNote.getNotification("password");
+    if (notification) {
+      is(notification.options.passwordNotificationType, aKind);
+    }
+    return notification;
 }
 
 
 /*
  * clickPopupButton
  *
  * Clicks the specified popup notification button.
  */
--- a/toolkit/modules/PopupNotifications.jsm
+++ b/toolkit/modules/PopupNotifications.jsm
@@ -639,16 +639,19 @@ PopupNotifications.prototype = {
       notificationsToShow.forEach(function (n) {
         // Remember the time the notification was shown for the security delay.
         n.timeShown = this.window.performance.now();
       }, this);
       this.panel.openPopup(anchorElement, "bottomcenter topleft");
       notificationsToShow.forEach(function (n) {
         this._fireCallback(n, NOTIFICATION_EVENT_SHOWN);
       }, this);
+      // This notification is used by tests to know when all the processing
+      // required to display the panel has happened.
+      this.panel.dispatchEvent(new this.window.CustomEvent("Shown"));
     });
   },
 
   /**
    * Updates the notification state in response to window activation or tab
    * selection changes.
    *
    * @param notifications an array of Notification instances. if null,
--- a/toolkit/mozapps/update/tests/TestAUSHelper.cpp
+++ b/toolkit/mozapps/update/tests/TestAUSHelper.cpp
@@ -94,38 +94,47 @@ CheckMsg(const NS_tchar *path, const cha
 
   FILE *inFP = NS_tfopen(path, NS_T("rb"));
   if (!inFP) {
     return false;
   }
 
   struct stat ms;
   if (fstat(fileno(inFP), &ms)) {
+    fclose(inFP);
+    inFP = nullptr;
     return false;
   }
 
   char *mbuf = (char *) malloc(ms.st_size + 1);
   if (!mbuf) {
+    fclose(inFP);
+    inFP = nullptr;
     return false;
   }
 
   size_t r = ms.st_size;
   char *rb = mbuf;
   size_t c = fread(rb, sizeof(char), 50, inFP);
   r -= c;
   rb += c;
   if (c == 0 && r) {
+    free(mbuf);
+    fclose(inFP);
+    inFP = nullptr;
     return false;
   }
   mbuf[ms.st_size] = '\0';
   rb = mbuf;
 
+  bool isMatch = strcmp(rb, expected) == 0;
+  free(mbuf);
   fclose(inFP);
   inFP = nullptr;
-  return strcmp(rb, expected) == 0;
+  return isMatch;
 }
 
 #ifdef XP_WIN
 /**
  * Verifies the trust of the specified file path.
  *
  * @param  filePath  The file path to check.
  * @return ERROR_SUCCESS if successful, or the last error code otherwise.
--- a/toolkit/themes/windows/global/aboutReader.css
+++ b/toolkit/themes/windows/global/aboutReader.css
@@ -23,21 +23,21 @@ body {
 
 .sepia,
 .sepia-button {
   color: #333333;
   background-color: #f0ece7;
 }
 
 .sans-serif {
-  font-family: sans-serif;
+  font-family: "Fira Sans", Helvetica, Arial, sans-serif;
 }
 
 .serif {
-  font-family: serif;
+  font-family: "Charis SIL", Georgia, "Times New Roman", serif;
 }
 
 .font-size1 {
   font-size: 10px;
 }
 
 .font-size2 {
   font-size: 12px;
@@ -88,17 +88,17 @@ body {
   text-align: start;
   display: none;
 }
 
 .domain {
   font-size: 0.9rem;
   line-height: 1.33rem;
   padding-bottom: 4px;
-  font-family: sans-serif;
+  font-family: "Fira Sans", Helvetica, Arial, sans-serif;
   text-decoration: none;
   border-bottom: 1px solid;
   color: #0095dd;
 }
 
 .light > .container > .header > .domain,
 .sepia > .container > .header > .domain {
   border-bottom-color: #333333;
@@ -226,17 +226,17 @@ body {
 .content ol {
   -moz-padding-start: 30px;
   list-style: decimal;
 }
 
 /*======= Controls toolbar =======*/
 
 .toolbar {
-  font-family: sans-serif;
+  font-family: "Fira Sans", Helvetica, Arial, sans-serif;
   position: fixed;
   height: 100%;
   top: 0px;
   left: 0px;
   margin: 0;
   padding: 0;
   list-style: none;
   background-color: #FBFBFB;
@@ -281,17 +281,17 @@ body {
   min-width: 250px;
   text-align: start;
   position: absolute;
   left: 48px; /* offset to account for toolbar width */
   z-index: 1000;
   background-color: #FBFBFB;
   visibility: hidden;
   border-radius: 4px;
-  border: 1px solid #B5B5B5;
+  border: 1px 1px 0 1px solid #B5B5B5;
   box-shadow: 0px 1px 12px #666;
 }
 
 .dropdown-popup > hr {
   width: 100%;
   height: 0px;
   border: 0px;
   border-top: 1px solid #B5B5B5;
@@ -314,16 +314,29 @@ body {
 
 #font-type-buttons,
 #font-size-buttons,
 #color-scheme-buttons {
   display: flex;
   flex-direction: row;
 }
 
+#font-type-buttons > button:first-child {
+  border-top-left-radius: 3px;
+}
+#font-type-buttons > button:last-child {
+  border-top-right-radius: 3px;
+}
+#color-scheme-buttons > button:first-child {
+  border-bottom-left-radius: 3px;
+}
+#color-scheme-buttons > button:last-child {
+  border-bottom-right-radius: 3px;
+}
+
 #font-type-buttons > button,
 #font-size-buttons > button,
 #color-scheme-buttons > button {
   text-align: center;
   border-left: 1px solid #B5B5B5;
   border-right: 0;
   border-top: 0;
   border-bottom: 0;
@@ -332,61 +345,63 @@ body {
 
 #font-type-buttons > button,
 #font-size-buttons > button {
   width: 50%;
   background-color: transparent;
 }
 
 #color-scheme-buttons > button {
-  width: 33%;
+  width: 33.33%;
   font-size: 14px;
 }
 
 #font-type-buttons > button:first-child,
 #font-size-buttons > button:first-child,
 #color-scheme-buttons > button:first-child {
   border-left: 0px;
 }
 
 #font-type-buttons > button {
   display: inline-block;
   font-size: 48px;
-  border-bottom: 3px solid transparent;
 }
 
 #font-type-buttons > button:active:hover,
-#font-type-buttons > button.selected {
-  border-bottom: 3px solid #FC6420;
+#font-type-buttons > button.selected,
+#color-scheme-buttons > button:active:hover,
+#color-scheme-buttons > button.selected {
+  box-shadow: inset 0 -3px 0 0 #FC6420;
 }
 
 #font-type-buttons > button > div {
   color: #666;
   font-size: 12px;
 }
 
 .button:hover,
-#font-size-buttons > button:hover {
+#font-size-buttons > button:hover,
+#font-type-buttons > button:hover {
   background-color: #EBEBEB;
 }
 
 .dropdown.open,
 .button:active,
 #font-size-buttons > button:active,
 #font-size-buttons > button.selected {
   background-color: #DADADA;
 }
 
 /* Only used on Android */
 #font-size-sample {
   display: none;
 }
 
 .serif-button {
-  font-family: serif;
+  font-family: "Charis SIL", Georgia, "Times New Roman", serif;
 }
 
 .minus-button,
 .plus-button {
   background-color: transparent;
   border: 0;
   height: 50px;
   background-size: 18px 18px;
@@ -434,8 +449,14 @@ body {
 
 .minus-button {
   background-image: url("chrome://global/skin/reader/RM-Minus-24x24.svg");
 }
 
 .plus-button {
   background-image: url("chrome://global/skin/reader/RM-Plus-24x24.svg");
 }
+
+@media print {
+  .toolbar {
+    display: none;
+  }
+}