Bug 1387557 - Transition to fatter progressbar. r=mikedeboer draft
authorSam Foster <sfoster@mozilla.com>
Tue, 12 Sep 2017 00:08:43 -0700
changeset 666419 faff440fa26d9ae2eb831a00ee0b502a64f51352
parent 666274 ffe6cc09ccf38cca6f0e727837bbc6cb722d1e71
child 732104 57ed6c585b88b159345118aa20b4041729b14a87
push id80406
push userbmo:sfoster@mozilla.com
push dateMon, 18 Sep 2017 18:44:13 +0000
reviewersmikedeboer
bugs1387557
milestone57.0a1
Bug 1387557 - Transition to fatter progressbar. r=mikedeboer * Pre-rendered animations to transition to the fatter progressbar * Frames of the indicator graphic in the notifier replace and overlay the button indicator, so that we can control the ease-in of the progressbar and transition of the arrow from an attention state * Forward selected attributes to the notifier element to drive animation behavior & specifics * Transition from not-downloading to downloading state in the notifier, revealing the indicator when the animation complete * Animate the transition from attention=success to none with a pre-rendered svg animation MozReview-Commit-ID: BDguf62lTyt
browser/components/downloads/content/indicator.js
browser/components/downloads/content/indicatorOverlay.xul
browser/themes/shared/downloads/download-icons.svg
browser/themes/shared/downloads/faux-indicator-animation.svg
browser/themes/shared/downloads/indicator-state-transition.svg
browser/themes/shared/downloads/indicator.inc.css
browser/themes/shared/downloads/inprogress-arrow.svg
browser/themes/shared/downloads/notification-start-animation.svg
browser/themes/shared/downloads/progressbar-start-animation.svg
browser/themes/shared/jar.inc.mn
--- a/browser/components/downloads/content/indicator.js
+++ b/browser/components/downloads/content/indicator.js
@@ -1,14 +1,15 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 /* eslint-env mozilla/browser-window */
+/* globals CustomizableUI, DownloadsCommon, browserDragAndDrop, gNavToolbox */
 
 /**
  * Handles the indicator that displays the progress of ongoing downloads, which
  * is also used as the anchor for the downloads panel.
  *
  * This module includes the following constructors and global objects:
  *
  * DownloadsButton
@@ -22,18 +23,16 @@
  * Builds and updates the actual downloads status widget, responding to changes
  * in the global status data, or provides a neutral view if the indicator is
  * removed from the toolbars and only used as a temporary anchor.  In addition,
  * handles the user interaction events raised by the widget.
  */
 
 "use strict";
 
-Components.utils.import("resource://gre/modules/AppConstants.jsm");
-
 // DownloadsButton
 
 /**
  * Main entry point for the downloads indicator.  Depending on how the toolbars
  * have been customized, this object determines if we should show a fully
  * functional indicator, a placeholder used during customization and in the
  * customization palette, or a neutral view as a temporary anchor for the
  * downloads panel.
@@ -146,16 +145,19 @@ const DownloadsButton = {
     let button = this._placeholder;
     if (!button && includePalette) {
       button = gNavToolbox.palette.querySelector("#downloads-button");
     }
     if (button && button.hasAttribute("hidden")) {
       button.removeAttribute("hidden");
       if (this._navBar.contains(button)) {
         this._navBar.setAttribute("downloadsbuttonshown", "true");
+        if (DownloadsCommon.animateNotifications) {
+          button.setAttribute("animateunhiding", "true");
+        }
       }
     }
   },
 
   hide() {
     let button = this._placeholder;
     if (this.autoHideDownloadsButton && button && button.closest("toolbar")) {
       DownloadsPanel.hidePanel();
@@ -420,61 +422,100 @@ const DownloadsIndicatorView = {
 
     // The notification element is positioned to show in the same location as
     // the downloads button. It's not in the downloads button itself in order to
     // be able to anchor the notification elsewhere if required, and to ensure
     // the notification isn't clipped by overflow properties of the anchor's
     // container.
     // Note: no notifier animation for download finished in Photon
     let notifier = this.notifier;
+    // This value is determined by the overall duration of animation in CSS.
+    let animationDuration = aType == "start" ? 760 : 850;
 
+    this._currentNotificationType = aType;
+
+    // This value is determined by the overall duration of animation in CSS.
     if (aType == "start") {
       // Show the notifier before measuring for size/placement. Being hidden by default
       // avoids the interference with scrolling/APZ when the notifier element is
       // tall enough to overlap the tabbrowser element
       notifier.removeAttribute("hidden");
 
-      // the anchor height may vary if font-size is changed or
-      // compact/tablet mode is selected so recalculate this each time
-      let anchorRect = anchor.getBoundingClientRect();
-      let notifierRect = notifier.getBoundingClientRect();
-      let topDiff = anchorRect.top - notifierRect.top;
-      let leftDiff = anchorRect.left - notifierRect.left;
-      let heightDiff = anchorRect.height - notifierRect.height;
-      let widthDiff = anchorRect.width - notifierRect.width;
-      let translateX = (leftDiff + .5 * widthDiff) + "px";
-      let translateY = (topDiff + .5 * heightDiff) + "px";
-      notifier.style.transform = "translate(" + translateX + ", " + translateY + ")";
-      notifier.setAttribute("notification", aType);
-    }
-    anchor.setAttribute("notification", aType);
+      requestAnimationFrame(() => {
+        // The anchor height may vary if font-size is changed or
+        // compact/tablet mode is selected so recalculate this each time
+        let anchorRect = anchor.getBoundingClientRect();
+        let notifierRect = notifier.getBoundingClientRect();
 
-    let animationDuration;
-    // This value is determined by the overall duration of animation in CSS.
-    animationDuration = aType == "start" ? 760 : 850;
+        let topDiff = anchorRect.top - notifierRect.top;
+        let leftDiff = anchorRect.left - notifierRect.left;
+        let heightDiff = anchorRect.height - notifierRect.height;
+        let widthDiff = anchorRect.width - notifierRect.width;
+        let translateX = (leftDiff + .5 * widthDiff) + "px";
+        let translateY = (topDiff + .5 * heightDiff) + "px";
+
+        // Forward selected attributes onto the notification element which will
+        // animate in the space over the downloads button
+
+        // Did the button just get un-hidden?
+        if (anchor.hasAttribute("animateunhiding")) {
+          notifier.setAttribute("animateunhiding", "true");
+        }
 
-    this._currentNotificationType = aType;
-
-    setTimeout(() => {
-      requestAnimationFrame(() => {
-        notifier.setAttribute("hidden", "true");
-        notifier.removeAttribute("notification");
-        notifier.style.transform = "";
-        anchor.removeAttribute("notification");
+        // Is the button in the overflow menu?
+        if (widget.overflowed) {
+          notifier.setAttribute("overflowed", "true");
+        }
+        // Is a previous download already in-progress?
+        if (anchor.hasAttribute("progress") &&
+            !anchor.hasAttribute("startprogress")) {
+          notifier.setAttribute("progress", "true");
+        } else if (this._attention !== DownloadsCommon.ATTENTION_NONE) {
+          // The indicator was in an attention state when download started.
+          notifier.setAttribute("attention", "true");
+        }
+        notifier.style.transform = "translate(" + translateX + ", " + translateY + ")";
+        notifier.setAttribute("notification", aType);
+        anchor.setAttribute("notification", aType);
 
-        requestAnimationFrame(() => {
-          let nextType = this._nextNotificationType;
-          this._currentNotificationType = null;
-          this._nextNotificationType = null;
-          if (nextType) {
-            this._showNotification(nextType);
-          }
-        });
+        setTimeout(() => {
+          requestAnimationFrame(() => this._showNotificationEnd(anchor, notifier));
+        }, animationDuration);
       });
-    }, animationDuration);
+    } else {
+      anchor.setAttribute("notification", aType);
+      setTimeout(() => {
+        requestAnimationFrame(() => this._showNotificationEnd(anchor));
+      }, animationDuration);
+    }
+  },
+
+  _showNotificationEnd(anchor, notifier) {
+    if (notifier) {
+      // Clear the attributes forwarded from the indicator earlier.
+      notifier.setAttribute("hidden", "true");
+      notifier.removeAttribute("notification");
+      notifier.removeAttribute("overflowed");
+      notifier.removeAttribute("progress");
+      notifier.removeAttribute("attention");
+      notifier.removeAttribute("animateunhiding");
+      notifier.style.transform = "";
+    }
+    anchor.removeAttribute("notification");
+    anchor.removeAttribute("startprogress");
+    anchor.removeAttribute("animateunhiding");
+
+    requestAnimationFrame(() => {
+      let nextType = this._nextNotificationType;
+      this._currentNotificationType = null;
+      this._nextNotificationType = null;
+      if (nextType) {
+        this._showNotification(nextType);
+      }
+    });
   },
 
   // Callback functions from DownloadsIndicatorData
 
   /**
    * Indicates whether the indicator should be shown because there are some
    * downloads to be displayed.
    */
@@ -502,22 +543,29 @@ const DownloadsIndicatorView = {
    * Progress indication to display, from 0 to 100, or -1 if unknown.
    * Progress is not visible if the current progress is unknown.
    */
   set percentComplete(aValue) {
     if (!this._operational) {
       return this._percentComplete;
     }
 
-    if (this._percentComplete !== aValue) {
+    let previousValue = this._percentComplete;
+    if (previousValue !== aValue) {
       this._percentComplete = aValue;
       this._refreshAttention();
 
       if (this._percentComplete >= 0) {
         this.indicator.setAttribute("progress", "true");
+        // Setter may be called before showEventNotification
+        // so mark the element when a new download begins.
+        // Attribute will be removed when the notification ends.
+        if (previousValue < 0 && DownloadsCommon.animateNotifications) {
+          this.indicator.setAttribute("startprogress", "true");
+        }
         // For arrow type only:
         // We set animationDelay to a minus value (0s ~ -100s) to show the
         // corresponding frame needed for progress.
         this._progressIcon.style.animationDelay = (-this._percentComplete) + "s";
       } else {
         this.indicator.removeAttribute("progress");
         this._progressIcon.style.animationDelay = "1s";
       }
@@ -546,22 +594,35 @@ const DownloadsIndicatorView = {
     let widgetGroup = CustomizableUI.getWidget("downloads-button");
     let inMenu = widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL;
 
     // For arrow-Styled indicator, suppress success attention if we have
     // progress in toolbar
     let suppressAttention = !inMenu &&
       this._attention == DownloadsCommon.ATTENTION_SUCCESS &&
       this._percentComplete >= 0;
+    let hadAttention = this.indicator.hasAttribute("attention");
 
     if (suppressAttention || this._attention == DownloadsCommon.ATTENTION_NONE) {
       this.indicator.removeAttribute("attention");
     } else {
       this.indicator.setAttribute("attention", this._attention);
     }
+    if (!inMenu && hadAttention && DownloadsCommon.animateNotifications &&
+        this._attention == DownloadsCommon.ATTENTION_NONE) {
+      let indicator = this.indicator;
+      indicator.setAttribute("animateindicator", "true");
+      indicator.addEventListener("animationend", function animListener(event) {
+        if (event.animationName == "downloads-attention-transition" &&
+            indicator.hasAttribute("animateindicator")) {
+          indicator.removeAttribute("animateindicator");
+          indicator.removeEventListener("animationend", animListener);
+        }
+      });
+    }
   },
   _attention: DownloadsCommon.ATTENTION_NONE,
 
   // User interface event functions
 
   onWindowUnload() {
     // This function is registered as an event listener, we can't use "this".
     DownloadsIndicatorView.ensureTerminated();
--- a/browser/components/downloads/content/indicatorOverlay.xul
+++ b/browser/components/downloads/content/indicatorOverlay.xul
@@ -24,11 +24,14 @@
          state changes, otherwise the panel could change its position or lose
          its arrow unexpectedly. -->
     <stack id="downloads-indicator-anchor"
            consumeanchor="downloads-button">
       <box id="downloads-indicator-icon"/>
       <stack id="downloads-indicator-progress-outer">
         <box id="downloads-indicator-progress-inner"/>
       </stack>
+      <hbox id="downloads-indicator-animatable-box">
+        <image id="downloads-indicator-animatable-image"/>
+      </hbox>
     </stack>
   </toolbarbutton>
 </overlay>
--- a/browser/themes/shared/downloads/download-icons.svg
+++ b/browser/themes/shared/downloads/download-icons.svg
@@ -6,19 +6,18 @@
     :root > use:not(:target),
     :root > g:not(:target) {
       display: none;
     }
   </style>
   <defs>
     <path id="arrow-icon" d="M7.293 12.725a1 1 0 0 0 1.414 0l5-5a1 1 0 0 0-1.414-1.413L9 9.605V1.019a1 1 0 0 0-2 0v8.586L3.707 6.312a1 1 0 0 0-1.414 1.413l5 5z"/>
     <path id="short-bar-icon" d="m 13,14 a 1,1 0 1 1 0,2 h -10 a 1,1 0 1 1 0,-2 z"/>
-    <path id="long-bar-icon" d="m 14,14 a 1,1 0 1 1 0,2 h -12 a 1,1 0 1 1 0,-2"/>
+    <path id="long-bar-icon" d="M14.193 13.32h-13a1.35 1.35 0 0 0 0 2.7h13a1.35 1.35 0 0 0 0 -2.7z"/>
   </defs>
   <use id="arrow" fill="context-fill" fill-opacity="context-fill-opacity" href="#arrow-icon"/>
   <g id="arrow-with-bar" fill="context-fill" fill-opacity="context-fill-opacity">
     <use href="#arrow-icon"/>
     <use href="#short-bar-icon"/>
   </g>
   <use id="default-bar" fill="context-fill" fill-opacity="context-fill-opacity" href="#short-bar-icon"/>
-  <use id="progress-bar-bg" fill="context-fill" fill-opacity="0.2" href="#long-bar-icon"/>
-  <use id="progress-bar-fg" fill="context-fill" fill-opacity="context-fill-opacity" href="#long-bar-icon"/>
+  <use id="progress-bar" fill="context-fill" fill-opacity="context-fill-opacity" href="#long-bar-icon"/>
 </svg>
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/downloads/faux-indicator-animation.svg
@@ -0,0 +1,98 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="1260" height="98">
+  <defs>
+    <path id="indicator" d="M25.692 55h-9.629a1 1 0 0 0 0 2h9.629a1 1 0 0 0 0 -2zm-5.399 -1.275a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025 0.999 0.999 0 0 0 0 1.388l5 5z"/>
+  </defs>
+  <svg x="0">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="42">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="84">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="126">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="168">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="210">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="252">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="294">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="336">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="378">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="420">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="462">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="504">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="546">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="588">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="630">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="672">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="714">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="756">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="798">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="840">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="882">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="924">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="966">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="1008">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="1050">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="1092">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="1134">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="1176">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+  <svg x="1218">
+    <use fill="context-stroke" href="#indicator"/>
+  </svg>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/downloads/indicator-state-transition.svg
@@ -0,0 +1,51 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="128" height="16">
+  <svg width="16" height="16">
+    <path fill="context-stroke" d="M7.364 11.41a.9.9 0 0 0 1.272 0l4.5-4.5a.9.9 0 0 0-1.273-1.272L8.9 8.603V.875a.9.9 0 0 0-1.8 0v7.727L4.136 5.64a.9.9 0 0 0-1.273 1.27l4.5 4.5z"/>
+    <path fill="context-stroke" d="M14.318 13.352H1.32a1.35 1.35 0 0 0 0 2.7h13a1.35 1.35 0 0 0 0-2.7z"/>
+  </svg>
+  <svg width="16" height="16" x="16">
+    <path fill="context-stroke" d="M7.364 11.41a.9.9 0 0 0 1.272 0l4.5-4.5a.9.9 0 0 0-1.273-1.272L8.9 8.603V.875a.9.9 0 0 0-1.8 0v7.727L4.136 5.64a.9.9 0 0 0-1.272 1.27l4.5 4.5z"/>
+    <path fill="context-stroke" d="M14.318 13.352H1.32a1.35 1.35 0 0 0 0 2.7h13a1.35 1.35 0 0 0 0-2.7z"/>
+  </svg>
+  <svg width="16" height="16" x="32">
+    <path fill="context-fill" fill-opacity=".074" d="M7.352 11.545a.917.917 0 0 0 1.296 0l4.583-4.583a.917.917 0 0 0-1.296-1.295L8.917 8.684V.815a.917.917 0 0 0-1.834 0v7.87L4.065 5.666a.916.916 0 0 0-1.296 1.296l4.583 4.583z"/>
+    <path fill="context-stroke" fill-opacity=".926" d="M7.358 11.5a.908.908 0 0 0 1.284 0l4.537-4.536a.907.907 0 0 0-1.283-1.282L8.907 8.67V.879a.908.908 0 0 0-1.814 0v7.79L4.104 5.683a.907.907 0 0 0-1.283 1.282L7.358 11.5z"/>
+    <path fill="context-fill" fill-opacity=".074" d="M14.047 13.465H1.609a1.292 1.292 0 0 0 0 2.584h12.438a1.292 1.292 0 0 0 0-2.584z"/>
+    <path fill="context-stroke" fill-opacity=".926" d="M14.047 13.465H1.609a1.292 1.292 0 0 0 0 2.584h12.438a1.292 1.292 0 0 0 0-2.584z"/>
+  </svg>
+  <svg width="16" height="16" x="48">
+    <path fill="context-fill" fill-opacity=".259" d="M7.34 11.762a.934.934 0 0 0 1.32 0l4.667-4.666a.933.933 0 0 0-1.32-1.319L8.933 8.85V.837a.934.934 0 0 0-1.866 0V8.85L3.993 5.777a.932.932 0 0 0-1.32 1.319l4.667 4.666z"/>
+    <path fill="context-stroke" fill-opacity=".741" d="M7.345 11.727a.927.927 0 0 0 1.31 0l4.63-4.63a.926.926 0 0 0-1.31-1.308l-3.05 3.049V.888a.926.926 0 0 0-1.85 0v7.95l-3.05-3.05a.925.925 0 0 0-1.31 1.31l4.63 4.629z"/>
+    <path fill="context-fill" fill-opacity=".259" d="M13.776 13.579H1.9a1.233 1.233 0 0 0 0 2.466h11.876a1.233 1.233 0 0 0 0-2.466z"/>
+    <path fill="context-stroke" fill-opacity=".741" d="M13.776 13.579H1.9a1.233 1.233 0 0 0 0 2.466h11.876a1.233 1.233 0 0 0 0-2.466z"/>
+  </svg>
+  <svg width="16" height="16" x="64">
+    <path fill="context-fill" fill-opacity=".5" d="M7.328 12.021a.95.95 0 0 0 1.344 0l4.75-4.75a.95.95 0 0 0-1.343-1.342L8.95 9.057V.9a.95.95 0 0 0-1.9 0v8.157L3.922 5.93a.95.95 0 0 0-1.344 1.34l4.75 4.75z"/>
+    <path fill="context-stroke" fill-opacity=".5" d="M7.328 12.02a.95.95 0 0 0 1.344 0l4.75-4.75a.95.95 0 0 0-1.343-1.342L8.95 9.057V.9a.95.95 0 0 0-1.9 0v8.157L3.922 5.928a.95.95 0 0 0-1.344 1.343l4.75 4.75z"/>
+    <path fill="context-fill" fill-opacity=".5" d="M13.505 13.692H2.191a1.175 1.175 0 0 0 0 2.35h11.314a1.175 1.175 0 0 0 0-2.35z"/>
+    <path fill="context-stroke" fill-opacity=".5" d="M13.505 13.692H2.191a1.175 1.175 0 0 0 0 2.35h11.314a1.175 1.175 0 0 0 0-2.35z"/>
+  </svg>
+  <svg width="16" height="16" x="80">
+    <path fill="context-fill" fill-opacity=".741" d="M7.317 12.28a.967.967 0 0 0 1.366 0l4.834-4.833A.967.967 0 0 0 12.15 6.08L8.967 9.264v-8.3a.967.967 0 0 0-1.934 0v8.3L3.85 6.081a.966.966 0 0 0-1.367 1.366l4.834 4.833z"/>
+    <path fill="context-stroke" fill-opacity=".259" d="M7.311 12.314c.381.38.997.38 1.378 0l4.87-4.87a.974.974 0 0 0-1.377-1.376L8.974 9.275V.912a.974.974 0 0 0-1.948 0v8.363L3.818 6.068a.973.973 0 0 0-1.377 1.376l4.87 4.87z"/>
+    <path fill="context-fill" fill-opacity=".741" d="M13.234 13.805H2.482a1.117 1.117 0 0 0 0 2.234h10.752a1.117 1.117 0 0 0 0-2.234z"/>
+    <path fill="context-stroke" fill-opacity=".259" d="M13.234 13.805H2.482a1.117 1.117 0 0 0 0 2.234h10.752a1.117 1.117 0 0 0 0-2.234z"/>
+  </svg>
+  <svg width="16" height="16" x="96">
+    <path fill="context-fill" fill-opacity=".926" d="M7.305 12.497a.984.984 0 0 0 1.39 0l4.917-4.916a.983.983 0 0 0-1.39-1.39L8.982 9.43V.987a.984.984 0 0 0-1.966 0v8.442L3.779 6.191a.982.982 0 0 0-1.39 1.39l4.916 4.916z"/>
+    <path fill="context-stroke" fill-opacity=".074" d="M7.298 12.54a.993.993 0 0 0 1.404 0l4.963-4.962a.993.993 0 0 0-1.404-1.403L8.993 9.444V.92a.993.993 0 0 0-1.986 0v8.523L3.74 6.175a.992.992 0 0 0-1.404 1.403l4.963 4.962z"/>
+    <path fill="context-fill" fill-opacity=".926" d="M12.963 13.919H2.772a1.058 1.058 0 0 0 0 2.116h10.19a1.058 1.058 0 0 0 0-2.116z"/>
+    <path fill="context-stroke" fill-opacity=".074" d="M12.963 13.919H2.772a1.058 1.058 0 0 0 0 2.116h10.19a1.058 1.058 0 0 0 0-2.116z"/>
+  </svg>
+  <svg width="16" height="16" x="112">
+    <path fill="context-fill" d="M7.293 12.631a1 1 0 0 0 1.414 0l5-5a1 1 0 0 0-1.414-1.413L9 9.511V.925a1 1 0 0 0-2 0v8.586L3.707 6.218a1 1 0 0 0-1.414 1.413l5 5z"/>
+    <path fill="context-fill" d="M12.692 14.032H3.063a1 1 0 0 0 0 2h9.629a1 1 0 0 0 0-2z"/>
+  </svg>
+  <svg width="16" height="16" x="128">
+    <path fill="context-stroke" d="M7.364 11.41a.9.9 0 0 0 1.272 0l4.5-4.5a.9.9 0 0 0-1.273-1.272L8.9 8.603V.875a.9.9 0 0 0-1.8 0v7.727L4.136 5.64a.9.9 0 0 0-1.273 1.27l4.5 4.5z"/>
+    <path fill="context-stroke" d="M14.318 13.352H1.32a1.35 1.35 0 0 0 0 2.7h13a1.35 1.35 0 0 0 0-2.7z"/>
+  </svg>
+</svg>
--- a/browser/themes/shared/downloads/indicator.inc.css
+++ b/browser/themes/shared/downloads/indicator.inc.css
@@ -4,46 +4,65 @@
 
 /*** Status and progress indicator ***/
 
 #downloads-indicator-anchor {
   min-width: 16px;
   min-height: 16px;
 }
 
+#downloads-indicator-icon {
+  -moz-context-properties: fill, fill-opacity;
+  background-image: url("chrome://browser/skin/downloads/download-icons.svg#arrow"),
+                    url("chrome://browser/skin/downloads/inprogress-arrow.svg");
+  background-size: 16px, 0px;
+  fill-opacity: 1;
+  width: 16px;
+  height: 16px;
+}
+
+#downloads-button[attention="success"] > #downloads-indicator-anchor > #downloads-indicator-icon  {
+  background-size: 0px, 16px;
+  fill: var(--toolbarbutton-icon-fill-attention);
+}
+
+/* show the smaller arrow when downloading. */
+#downloads-button[progress] > #downloads-indicator-anchor > #downloads-indicator-icon {
+  background-size: 0px, 16px;
+}
+
 #downloads-indicator-progress-outer {
   width: 16px;
   height: 16px;
   background-size: 16px;
-  background: url("chrome://browser/skin/downloads/download-icons.svg#default-bar") center no-repeat;
+  background-repeat: no-repeat;
+  background-position: center;
+  -moz-context-properties: fill, fill-opacity;
+  fill-opacity: 1;
+  background-image: url("chrome://browser/skin/downloads/download-icons.svg#default-bar");
 }
 
-#downloads-button[attention="success"] > #downloads-indicator-anchor > #downloads-indicator-icon,
-#downloads-button[attention="success"] > #downloads-indicator-anchor > #downloads-indicator-progress-outer {
-  -moz-context-properties: fill, fill-opacity;
+/* show the fatter progressbar when downloading and on successful download */
+#downloads-button[attention="success"] #downloads-indicator-progress-outer {
+  background-image: url("chrome://browser/skin/downloads/download-icons.svg#progress-bar");
   fill: var(--toolbarbutton-icon-fill-attention);
-  fill-opacity: 1;
 }
-#downloads-button[progress] > #downloads-indicator-anchor > #downloads-indicator-progress-outer {
-  background: url("chrome://browser/skin/downloads/download-icons.svg#progress-bar-bg") center no-repeat;
-}
-
-#downloads-indicator-icon {
-  -moz-context-properties: fill, fill-opacity;
-  background-image: url("chrome://browser/skin/downloads/download-icons.svg#arrow");
-  width: 16px;
-  height: 16px;
+#downloads-button[progress] #downloads-indicator-progress-outer  {
+  background-image: url("chrome://browser/skin/downloads/download-icons.svg#progress-bar");
+  fill-opacity: 0.2;
 }
 
 #downloads-indicator-progress-inner {
-  background: url("chrome://browser/skin/downloads/download-icons.svg#progress-bar-fg") left no-repeat;
+  background: url("chrome://browser/skin/downloads/download-icons.svg#progress-bar") left no-repeat;
   margin-right: 16px;
-  -moz-context-properties: fill;
+  -moz-context-properties: fill, fill-opacity;
+  fill-opacity: 1;
   fill: var(--toolbarbutton-icon-fill-attention);
   background-size: 16px;
+
   /* From javascript side we use animation delay from 0s to -100s to show
    * corresponding frames needed for progress.
    * animation-delay is set to a positive value to make nothing shown.
    */
   animation-play-state: paused;
   animation-delay: 1s;
   animation-duration: 100s;
   animation-timing-function: linear;
@@ -52,16 +71,33 @@
 
 #downloads-indicator-progress-inner:-moz-locale-dir(rtl) {
   background-position: right;
   animation-name: indicatorArrowProgressRTL;
   margin-left: 16px;
   margin-right: 0;
 }
 
+/* When a download starts (and animated notifications are enabled) we'll hide
+   the indicator while the notification plays.
+   startprogress is set when a download first starts and is removed when the notification ends.
+   If a download was already in progress, we do want to show it
+   Note: sometimes download progress/attention is set before the notification event,
+   othertimes not.
+   */
+#downloads-button[startprogress] #downloads-indicator-anchor,
+#downloads-button[notification="start"] #downloads-indicator-anchor {
+  visibility: hidden;
+}
+
+#downloads-button:not([startprogress])[progress] #downloads-indicator-anchor,
+#downloads-button[notification="start"]:not([startprogress])[progress] #downloads-indicator-anchor {
+  visibility: visible;
+}
+
 @keyframes indicatorArrowProgress {
   0% {
     margin-right: 15px;
   }
   100% {
     margin-right: 1px;
   }
 }
@@ -70,16 +106,67 @@
   0% {
     margin-left: 15px;
   }
   100% {
     margin-left: 1px;
   }
 }
 
+@keyframes downloads-attention-transition {
+  0% { transform: translateX(0px); }
+  100% { transform: translateX(-112px); }
+}
+
+#downloads-button[animateindicator],
+#downloads-button[startprogress] {
+  fill: transparent;
+}
+
+#downloads-indicator-animatable-box {
+  overflow: hidden;
+  min-width: 16px;
+  min-height: 16px;
+  max-width: 16px;
+  max-height: 16px;
+  visibility: hidden;
+  list-style-image: none;
+  /* animation is not directional and shouldn't be reversed in RTL */
+  direction: ltr;
+}
+
+#downloads-button[animateindicator] #downloads-indicator-animatable-box {
+  visibility: visible;
+}
+#downloads-button[animateindicator] > #downloads-indicator-anchor > #downloads-indicator-icon,
+#downloads-button[animateindicator] > #downloads-indicator-anchor > #downloads-indicator-progress-outer {
+  visibility: hidden;
+}
+
+#downloads-indicator-animatable-image {
+  background-image: url(chrome://browser/skin/downloads/indicator-state-transition.svg);
+  background-repeat: no-repeat;
+  background-position: left center;
+  min-width: 128px;
+  max-width: 128px;
+  min-height: 16px;
+  max-height: 16px;
+  -moz-context-properties: fill, stroke;
+  stroke: var(--toolbarbutton-icon-fill-attention);
+  fill: currentColor;
+}
+
+/* play an animation when the button changes from attention to none state */
+#downloads-button:not([notification])[animateindicator] #downloads-indicator-animatable-image {
+  animation-name: downloads-attention-transition;
+  animation-duration: 116.67ms;
+  animation-timing-function: steps(7);
+  animation-fill-mode: forwards;
+}
+
 /*** Status badges ***/
 
 #downloads-button[attention="warning"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
 #downloads-button[attention="severe"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
   display: -moz-box;
   height: 8px;
   width: 8px;
   min-width: 0;
@@ -104,43 +191,50 @@
 
 #downloads-button[attention="severe"] > .toolbarbutton-badge-stack > .toolbarbutton-badge:-moz-window-inactive,
 #downloads-button[attention="warning"] > .toolbarbutton-badge-stack > .toolbarbutton-badge:-moz-window-inactive {
   filter: none;
 }
 
 /*** Download notifications ***/
 
-#downloads-button[notification="start"] > #downloads-indicator-anchor > #downloads-indicator-icon {
-  animation-name: downloadsIndicatorStartDip;
-  /* Upon changing the duration_delay below, please keep the delay time of
-     setTimeout() identical in indicator.js for this animation.
+/* We distinguish between 3 scenarios:
+   Download indicator not currently in toolbar, e.g. first download of the session
+   Indicator in toolbar, no download currently in progress
+   Download already in progress
+*/
 
-     Timing here needs to align with the animation on #downloads-indicator-notification
-  */
-  animation-duration: 360ms;
-  animation-delay: 400ms;
-  animation-iteration-count: 1;
+@keyframes downloadsNotifierArrowDropIndicatorDip {
+  from {
+    transform: translateX(0);
+  }
+  to {
+    transform: translateX(-1722px);
+  }
 }
 
-@keyframes downloadsIndicatorStartDip {
-  0% {
-    transform: translateY(0);
-    animation-timing-function: linear;
+@keyframes downloadsNotifierArrowDrop {
+  from {
+    transform: translateX(0);
+  }
+  to {
+    transform: translateX(-1218px);
   }
-  50% {
-    transform: translateY(0);
-    animation-timing-function: ease-out;
+}
+
+/*
+  To ensure the indicator is made visible in the correct frame, we use an
+  animation run in parallel with the start notifications (downloadsNotifierArrowDrop_ animations
+*/
+@keyframes downloadsIndicatorAppear {
+  0% {
+    visibility: hidden;
   }
-  88% {
-    transform: translateY(3px);
-    animation-timing-function: ease-out;
-  }
-  100% {
-    transform: translateY(0);
+  99.9% {
+    visibility: visible;
   }
 }
 
 @keyframes downloadsIndicatorFinishPulse {
   from  { transform: scale(1); }
   37.5% { transform: scale(1.4); animation-timing-function: ease-out; }
   to    { transform: scale(1); animation-timing-function: ease-in; }
 }
@@ -176,32 +270,59 @@
   max-height: 98px;
   overflow: hidden;
   /* animation is not directional and shouldn't be reversed in RTL */
   direction: ltr;
 }
 
 #downloads-indicator-notification {
   opacity: 0;
-  min-width: 1344px;
+  min-width: 1764px; /* The full combined width of the svg filmstrip images */
   height: 98px; /* Height is equal to height of each frame in the SVG animation */
-  -moz-context-properties: fill;
-  fill: #737373;
+  -moz-context-properties: fill, stroke;
+  fill: #494949;
+  stroke: #494949;
+  /* Preload the animation images */
+  background-image: url('chrome://browser/skin/downloads/notification-start-animation.svg'), /* the arrow-drop animation */
+                    url('chrome://browser/skin/downloads/progressbar-start-animation.svg'),  /* the ease-in of the progressbar on first use */
+                    url('chrome://browser/skin/downloads/faux-indicator-animation.svg'); /* a static indicator animation to replace a real one during the animation */
+  background-size: 0px, 0px, 0px;
+  background-repeat: no-repeat;
+  background-position: 0 center;
+}
+
+#downloads-notification-anchor[attention] > #downloads-indicator-notification {
+  stroke: var(--toolbarbutton-icon-fill-attention);
 }
 
-@keyframes downloadsIndicatorNotificationStart {
-  from {
-    transform: translateX(0);
-  }
-  to {
-    transform: translateX(-1302px);
-  }
+/* download starts - first of the session */
+#downloads-notification-anchor[notification="start"][animateunhiding] > #downloads-indicator-notification {
+  opacity: 1;
+  /* show notifier arrow, progressbar ease-in */
+  background-size: 1764px 98px, 1260px 98px, 0 0;
+  animation-name: downloadsNotifierArrowDropIndicatorDip;
+  animation-duration: 0.683s;
+  animation-timing-function: steps(41);
+  animation-fill-mode: forwards;
 }
 
+/* download starts, no download current in-progress */
 #downloads-notification-anchor[notification="start"] > #downloads-indicator-notification {
   opacity: 1;
-  background: url("chrome://browser/skin/downloads/notification-start-animation.svg") 0 center no-repeat;
+  /* show notifier arrow and indicator replacement */
+  background-size: 1764px 98px, 0 0, 1260px 98px;
+  animation-name: downloadsNotifierArrowDropIndicatorDip;
+  animation-duration: 0.683s;
+  animation-timing-function: steps(41);
+}
+
+/* download starts, download already in-progress
+   or download button in overflow menu */
+#downloads-notification-anchor[progress][notification="start"] > #downloads-indicator-notification,
+#downloads-notification-anchor[overflowed][notification="start"] > #downloads-indicator-notification {
+  opacity: 1;
+  /* just show notifier arrow - the first 29 frames of notification-start-animation.svg  */
+  background-size: 1764px 98px, 0 0, 0 0;
   transform: translateX(0px);
-  animation-name: downloadsIndicatorNotificationStart;
-  animation-duration: 540ms;
-  animation-delay: 64ms;
-  animation-timing-function: steps(31);
+  animation-name: downloadsNotifierArrowDrop;
+  animation-timing-function: steps(29);
+  animation-duration: 0.483s;
 }
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/downloads/inprogress-arrow.svg
@@ -0,0 +1,6 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <path fill="context-fill" d="M7.24 11.4a .900,.900 0 0 0 1.27 0l4.50-4.50a .900,.900 0 0 0-1.27-1.27l-2.96 2.96v-7.73a .900,.900 0 0 0-1.80 0v7.73l-2.96-2.96a .900,.900 0 0 0-1.27 .0200a .900,.900 0 0 0 0 1.25l4.50 4.50z"/>
+</svg>
--- a/browser/themes/shared/downloads/notification-start-animation.svg
+++ b/browser/themes/shared/downloads/notification-start-animation.svg
@@ -1,95 +1,159 @@
 <!-- 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/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="1344" height="98">
-  <svg width="42" height="98"/>
-  <svg width="42" height="98" x="42"/>
+<svg xmlns="http://www.w3.org/2000/svg" width="1764" height="98">
+  <defs>
+    <clipPath id="f30_animationMask_558KQGBcMr">
+      <path d="M0 0h42v59h-42z"/>
+    </clipPath>
+    <clipPath id="f30_uW1U4lQV3i">
+      <path fill="#fff" d="M1.688 14v2h12.373v-2h-12.373"/>
+    </clipPath>
+    <path id="notifyarrow" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z"/>
+    <path id="indicatorarrow" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025 0.999 0.999 0 0 0 0 1.388l5 5z"/>
+    <path id="bar" d="M4.629 -1h-9.629a1 1 0 0 0 0 2h9.629a1 1 0 0 0 0 -2z"/>
+  </defs>
+  <svg width="42" height="98" x="0"/>
+  <svg width="42" height="98" x="42">
+    <use fill="context-fill" fill-opacity=".257" href="#notifyarrow" transform="translate(21.018 22.854) scale(3.50932)"/>
+  </svg>
   <svg width="42" height="98" x="84">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" opacity=".333" transform="translate(21.018 22.854) scale(3.50932)"/>
+    <use fill="context-fill" fill-opacity=".52" href="#notifyarrow" transform="translate(21.017 23.815) scale(3.41419)"/>
   </svg>
   <svg width="42" height="98" x="126">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" opacity=".667" transform="translate(21.017 23.815) scale(3.41419)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.017 24.798) scale(3.31695)"/>
   </svg>
   <svg width="42" height="98" x="168">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.017 24.798) scale(3.31695)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.016 25.793) scale(3.21855)"/>
   </svg>
   <svg width="42" height="98" x="210">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.016 25.793) scale(3.21855)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.016 26.795) scale(3.11952)"/>
   </svg>
   <svg width="42" height="98" x="252">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.016 26.795) scale(3.11952)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.015 27.8) scale(3.02017)"/>
   </svg>
   <svg width="42" height="98" x="294">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.015 27.8) scale(3.02017)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.015 28.805) scale(2.92072)"/>
   </svg>
   <svg width="42" height="98" x="336">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.015 28.805) scale(2.92072)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.014 29.81) scale(2.82134)"/>
   </svg>
   <svg width="42" height="98" x="378">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.014 29.81) scale(2.82134)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.014 30.813) scale(2.72216)"/>
   </svg>
   <svg width="42" height="98" x="420">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.014 30.813) scale(2.72216)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.013 31.813) scale(2.6233)"/>
   </svg>
   <svg width="42" height="98" x="462">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.013 31.813) scale(2.6233)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.013 32.809) scale(2.52484)"/>
   </svg>
   <svg width="42" height="98" x="504">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.013 32.809) scale(2.52484)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.012 33.799) scale(2.42691)"/>
   </svg>
   <svg width="42" height="98" x="546">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.012 33.799) scale(2.42691)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.012 34.783) scale(2.32959)"/>
   </svg>
   <svg width="42" height="98" x="588">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.012 34.783) scale(2.32959)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.011 35.76) scale(2.23297)"/>
   </svg>
   <svg width="42" height="98" x="630">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.011 35.76) scale(2.23297)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.01 36.727) scale(2.13718)"/>
   </svg>
   <svg width="42" height="98" x="672">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.01 36.727) scale(2.13718)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.01 37.686) scale(2.0423)"/>
   </svg>
   <svg width="42" height="98" x="714">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.01 37.686) scale(2.0423)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.01 38.634) scale(1.94849)"/>
   </svg>
   <svg width="42" height="98" x="756">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.01 38.634) scale(1.94849)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.01 39.57) scale(1.85587)"/>
   </svg>
   <svg width="42" height="98" x="798">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.01 39.57) scale(1.85587)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.009 40.491) scale(1.76462)"/>
   </svg>
   <svg width="42" height="98" x="840">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.009 40.491) scale(1.76462)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.008 41.397) scale(1.67492)"/>
   </svg>
   <svg width="42" height="98" x="882">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.008 41.397) scale(1.67492)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.008 42.284) scale(1.58703)"/>
   </svg>
   <svg width="42" height="98" x="924">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.008 42.284) scale(1.58703)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.008 43.15) scale(1.50124)"/>
   </svg>
   <svg width="42" height="98" x="966">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.008 43.15) scale(1.50124)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.007 43.99) scale(1.41793)"/>
   </svg>
   <svg width="42" height="98" x="1008">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.007 43.99) scale(1.41793)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.007 44.8) scale(1.33758)"/>
   </svg>
   <svg width="42" height="98" x="1050">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.007 44.8) scale(1.33758)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.006 45.573) scale(1.26087)"/>
   </svg>
   <svg width="42" height="98" x="1092">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.006 45.573) scale(1.26087)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.006 46.299) scale(1.18877)"/>
   </svg>
   <svg width="42" height="98" x="1134">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.006 46.299) scale(1.18877)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.006 46.963) scale(1.1227)"/>
   </svg>
   <svg width="42" height="98" x="1176">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.006 46.963) scale(1.1227)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.005 47.541) scale(1.0651)"/>
   </svg>
   <svg width="42" height="98" x="1218">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.005 47.541) scale(1.0651)"/>
+    <use fill="context-fill" fill-opacity="0.78" href="#notifyarrow" transform="translate(21.005 47.988) scale(1.02049)"/>
   </svg>
+
   <svg width="42" height="98" x="1260">
-    <path fill="context-fill" d="M-0.712 6.158a1 1 0 0 0 1.414 0l5 -5a1 1 0 0 0 -1.414 -1.413l-3.293 3.293v-8.586a1 1 0 0 0 -2 0v8.586l-3.293 -3.293a1 1 0 0 0 -1.414 0.025a0.999 0.999 0 0 0 0 1.388l5 5z" transform="translate(21.005 47.988) scale(1.02049)"/>
+    <use fill="context-fill" fill-opacity="0.2" href="#bar" transform="matrix(1.35 0 0 1.35 20.975 56.514)"/>
+    <g clip-path="url(#f30_uW1U4lQV3i)">
+      <path fill="context-fill" href="#bar" transform="matrix(1.35 0 0 1.35 20.975 56.514)"/>
+      </g>
+      <use fill="context-stroke" href="#indicatorarrow" transform="translate(20.91 48.555) scale(.98585)"/>
+  </svg>
+  <svg width="42" height="98" x="1302">
+    <use fill="context-fill" fill-opacity="0.2" href="#bar" transform="translate(20.975 56.47) scale(1.39697)"/>
+    <use fill="context-stroke" href="#indicatorarrow" transform="translate(20.911 48.946) scale(.99283)"/>
+  </svg>
+  <svg width="42" height="98" x="1344">
+    <use fill="context-fill" fill-opacity="0.2" href="#bar" transform="translate(20.977 56.376) scale(1.49637)"/>
+    <use fill="context-stroke" href="#indicatorarrow" transform="translate(20.911 49.23) scale(.9979)"/>
+  </svg>
+  <svg width="42" height="98" x="1386">
+    <use fill="context-fill" fill-opacity="0.2" href="#bar" transform="translate(20.979 56.266) scale(1.61367)"/>
+    <use fill="context-stroke" href="#indicatorarrow" transform="translate(20.911 49.348)"/>
+  </svg>
+  <svg width="42" height="98" x="1428">
+    <use fill="context-fill" fill-opacity="0.2" href="#bar" transform="matrix(1.7 0 0 1.7 20.98 56.185)"/>
+    <use fill="context-fill" href="#indicatorarrow" transform="translate(20.911 48.918) scale(.99234)"/>
+  </svg>
+  <svg width="42" height="98" x="1470">
+    <use fill="context-fill" fill-opacity="0.2" href="#bar" transform="translate(20.98 56.235) scale(1.6465)"/>
+    <use fill="context-fill" href="#indicatorarrow" transform="translate(20.91 48.449) scale(.98396)"/>
   </svg>
-  <svg width="42" height="98" x="1302"/>
+  <svg width="42" height="98" x="1512">
+    <use fill="context-fill" fill-opacity="0.2" href="#bar" transform="translate(20.978 56.31) scale(1.56687)"/>
+    <use fill="context-fill" href="#indicatorarrow" transform="translate(20.91 47.99) scale(.97578)"/>
+  </svg>
+  <svg width="42" height="98" x="1554">
+    <use fill="context-fill" fill-opacity="0.2" href="#bar" transform="translate(20.977 56.389) scale(1.48313)"/>
+    <use fill="context-fill" href="#indicatorarrow" transform="translate(20.91 47.563) scale(.96816)"/>
+  </svg>
+  <svg width="42" height="98" x="1596">
+    <use fill="context-fill" fill-opacity="0.2" href="#bar" transform="translate(20.975 56.464) scale(1.4035)"/>
+    <use fill="context-fill" href="#indicatorarrow" transform="translate(20.91 47.182) scale(.96135)"/>
+  </svg>
+  <svg width="42" height="98" x="1638">
+    <use fill="context-fill" fill-opacity="0.2" href="#bar" transform="matrix(1.35 0 0 1.35 20.975 56.514)"/>
+    <use fill="context-fill" href="#indicatorarrow" transform="translate(20.91 46.864) scale(.95569)"/>
+  </svg>
+  <svg width="42" height="98" x="1680">
+    <use fill="context-fill" fill-opacity="0.2" href="#bar" transform="matrix(1.35 0 0 1.35 20.975 56.514)"/>
+    <use fill="context-fill" href="#indicatorarrow" transform="translate(20.91 46.637) scale(.95164)"/>
+  </svg>
+  <svg width="42" height="98" x="1722">
+    <use fill="context-fill" fill-opacity="0.2" href="#bar" transform="matrix(1.35 0 0 1.35 20.975 56.514)"/>
+    <g clip-path="url(#f30_uW1U4lQV3i)">
+      <use fill="context-fill" href="#bar" transform="matrix(1.35 0 0 1.35 20.975 56.514)"/>
+    </g>
+    <use fill="context-fill" href="#indicatorarrow" transform="matrix(.95 0 0 .95 20.91 47.546)"/>
+  </svg>
 </svg>
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/downloads/progressbar-start-animation.svg
@@ -0,0 +1,167 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="1260" height="98">
+  <defs>
+    <clipPath id="a">
+      <path fill="#fff" d="M1.134 15.616v2.236h13.194v-2.236h-13.194"/>
+    </clipPath>
+    <clipPath id="b">
+      <path fill="#fff" d="M0.926 14.806v2.293h13.57v-2.293h-13.57"/>
+    </clipPath>
+    <clipPath id="c">
+      <path fill="#fff" d="M0.763 14.167v2.338h13.865v-2.338h-13.865"/>
+    </clipPath>
+    <path id="progressbar" d="M12.629 14h-9.629a1 1 0 0 0 0 2h9.629a1 1 0 0 0 0 -2z"/>
+  </defs>
+  <svg width="42" height="98">
+    <g clip-path="url(#a)" transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="42">
+    <g clip-path="url(#b)" transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="84">
+    <g clip-path="url(#c)" transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="126">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="168">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="210">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="252">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="294">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="336">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="378">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="420">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="462">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="504">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="546">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="588">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="630">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="672">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="714">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="756">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="798">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="840">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="882">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="924">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="966">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="1008">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="1050">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="1092">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="1134">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="1176">
+    <g transform="translate(12.938 42)">
+      <use fill="context-fill" fill-opacity="0.2" href="#progressbar"/>
+    </g>
+  </svg>
+  <svg width="42" height="98" x="1218">
+    <g transform="translate(12.938 42)">
+      <path fill="context-use" fill-opacity=".33" href="#progressbar"/>
+    </g>
+  </svg>
+</svg>
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -42,16 +42,20 @@
   skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl@2x.png  (../shared/customizableui/subView-arrow-back-inverted-rtl@2x.png)
   skin/classic/browser/customizableui/whimsy.png               (../shared/customizableui/whimsy.png)
   skin/classic/browser/customizableui/whimsy@2x.png            (../shared/customizableui/whimsy@2x.png)
   skin/classic/browser/downloads/contentAreaDownloadsView.css  (../shared/downloads/contentAreaDownloadsView.css)
   skin/classic/browser/downloads/download-blocked.svg          (../shared/downloads/download-blocked.svg)
   skin/classic/browser/downloads/download-summary.svg          (../shared/downloads/download-summary.svg)
   skin/classic/browser/downloads/download-icons.svg            (../shared/downloads/download-icons.svg)
   skin/classic/browser/downloads/notification-start-animation.svg  (../shared/downloads/notification-start-animation.svg)
+  skin/classic/browser/downloads/progressbar-start-animation.svg  (../shared/downloads/progressbar-start-animation.svg)
+  skin/classic/browser/downloads/faux-indicator-animation.svg  (../shared/downloads/faux-indicator-animation.svg)
+  skin/classic/browser/downloads/inprogress-arrow.svg          (../shared/downloads/inprogress-arrow.svg)
+  skin/classic/browser/downloads/indicator-state-transition.svg  (../shared/downloads/indicator-state-transition.svg)
   skin/classic/browser/drm-icon.svg                            (../shared/drm-icon.svg)
   skin/classic/browser/fullscreen/insecure.svg                 (../shared/fullscreen/insecure.svg)
   skin/classic/browser/fullscreen/secure.svg                   (../shared/fullscreen/secure.svg)
   skin/classic/browser/connection-secure.svg                   (../shared/identity-block/connection-secure.svg)
   skin/classic/browser/connection-mixed-passive-loaded.svg     (../shared/identity-block/connection-mixed-passive-loaded.svg)
   skin/classic/browser/connection-mixed-active-loaded.svg      (../shared/identity-block/connection-mixed-active-loaded.svg)
   skin/classic/browser/identity-icon.svg                       (../shared/identity-block/identity-icon.svg)
   skin/classic/browser/identity-icon-notice.svg                (../shared/identity-block/identity-icon-notice.svg)