diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
index ca3c40bd1e64..65ec0ced5dcd 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -237,6 +237,8 @@ pref("general.autoScroll", false);
pref("general.autoScroll", true);
#endif
+pref("browser.stopReloadAnimation.enabled", true);
+
// UI density of the browser chrome. This mostly affects toolbarbutton
// and urlbar spacing. The possible values are 0=normal, 1=compact, 2=touch.
pref("browser.uidensity", 0);
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 6f7525a015eb..7dc617c4c3b2 100755
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4561,7 +4561,7 @@ var XULBrowserWindow = {
// XXX: This needs to be based on window activity...
this.stopCommand.removeAttribute("disabled");
- CombinedStopReload.switchToStop();
+ CombinedStopReload.switchToStop(aRequest, aWebProgress);
}
} else if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
// This (thanks to the filter) is a network stop or the last
@@ -4615,7 +4615,7 @@ var XULBrowserWindow = {
this._busyUI = false;
this.stopCommand.setAttribute("disabled", "true");
- CombinedStopReload.switchToReload(aRequest instanceof Ci.nsIRequest);
+ CombinedStopReload.switchToReload(aRequest, aWebProgress);
}
}
},
@@ -4921,41 +4921,107 @@ var CombinedStopReload = {
stop.addEventListener("click", this);
this.reload = reload;
this.stop = stop;
+ this.stopReloadContainer = this.reload.parentNode;
+
+ // Disable animations until the browser has fully loaded.
+ this.animate = false;
+ let startupInfo = Cc["@mozilla.org/toolkit/app-startup;1"]
+ .getService(Ci.nsIAppStartup)
+ .getStartupInfo();
+ if (startupInfo.sessionRestored) {
+ this.startAnimationPrefMonitoring();
+ } else {
+ Services.obs.addObserver(this, "sessionstore-windows-restored");
+ }
},
uninit() {
if (!this._initialized)
return;
+ Services.prefs.removeObserver("toolkit.cosmeticAnimations.enabled", this);
this._cancelTransition();
this._initialized = false;
this.stop.removeEventListener("click", this);
+ this.stopReloadContainer.removeEventListener("animationend", this);
+ this.stopReloadContainer = null;
this.reload = null;
this.stop = null;
},
handleEvent(event) {
- // the only event we listen to is "click" on the stop button
- if (event.button == 0 &&
- !this.stop.disabled)
- this._stopClicked = true;
+ switch (event.type) {
+ case "click":
+ if (event.button == 0 &&
+ !this.stop.disabled) {
+ this._stopClicked = true;
+ }
+ case "animationend": {
+ if (event.target.classList.contains("toolbarbutton-animatable-image") &&
+ (event.animationName == "reload-to-stop" ||
+ event.animationName == "stop-to-reload" ||
+ event.animationName == "reload-to-stop-rtl" ||
+ event.animationName == "stop-to-reload-rtl")) {
+ this.stopReloadContainer.removeAttribute("animate");
+ }
+ }
+ }
},
- switchToStop() {
+ observe(subject, topic, data) {
+ if (topic == "sessionstore-windows-restored") {
+ Services.obs.removeObserver(this, "sessionstore-windows-restored");
+ this.startAnimationPrefMonitoring();
+ } else if (topic == "nsPref:changed") {
+ this.animate = Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled");
+ }
+ },
+
+ startAnimationPrefMonitoring() {
+ requestIdleCallback(() => {
+ this.animate = Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled") &&
+ Services.prefs.getBoolPref("browser.stopReloadAnimation.enabled");
+ Services.prefs.addObserver("toolkit.cosmeticAnimations.enabled", this);
+ this.stopReloadContainer.addEventListener("animationend", this);
+ });
+ },
+
+ switchToStop(aRequest, aWebProgress) {
if (!this._initialized)
return;
+ let shouldAnimate = AppConstants.MOZ_PHOTON_ANIMATIONS &&
+ aRequest instanceof Ci.nsIRequest &&
+ aWebProgress.isTopLevel &&
+ aWebProgress.isLoadingDocument &&
+ this.animate;
+
this._cancelTransition();
+ if (shouldAnimate)
+ this.stopReloadContainer.setAttribute("animate", "true");
+ else
+ this.stopReloadContainer.removeAttribute("animate");
this.reload.setAttribute("displaystop", "true");
},
- switchToReload(aDelay) {
+ switchToReload(aRequest, aWebProgress) {
if (!this._initialized)
return;
+ let shouldAnimate = AppConstants.MOZ_PHOTON_ANIMATIONS &&
+ aRequest instanceof Ci.nsIRequest &&
+ aWebProgress.isTopLevel &&
+ !aWebProgress.isLoadingDocument &&
+ this.animate;
+
+ if (shouldAnimate)
+ this.stopReloadContainer.setAttribute("animate", "true");
+ else
+ this.stopReloadContainer.removeAttribute("animate");
+
this.reload.removeAttribute("displaystop");
- if (!aDelay || this._stopClicked) {
+ if (!shouldAnimate || this._stopClicked) {
this._stopClicked = false;
this._cancelTransition();
this.reload.disabled = XULBrowserWindow.reloadCommand
diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul
index 551cc2b3c618..655e6fd649c7 100644
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -786,11 +786,19 @@
class="toolbarbutton-1"
command="Browser:ReloadOrDuplicate"
onclick="checkForMiddleClick(this, event);"
- tooltip="dynamic-shortcut-tooltip"/>
+ tooltip="dynamic-shortcut-tooltip">
+
+
+
+
+ tooltip="dynamic-shortcut-tooltip">
+
+
+
+
#endif
diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml
index dd7167bad80d..bbec858740c1 100644
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1125,12 +1125,10 @@
this.showTab(this.mCurrentTab);
var forwardButtonContainer = document.getElementById("urlbar-wrapper");
- if (forwardButtonContainer) {
- forwardButtonContainer.setAttribute("switchingtabs", "true");
- window.addEventListener("MozAfterPaint", function() {
- forwardButtonContainer.removeAttribute("switchingtabs");
- }, {once: true});
- }
+ forwardButtonContainer.setAttribute("switchingtabs", "true");
+ window.addEventListener("MozAfterPaint", function() {
+ forwardButtonContainer.removeAttribute("switchingtabs");
+ }, {once: true});
this._appendStatusPanel();
diff --git a/browser/themes/shared/icons/reload-to-stop.svg b/browser/themes/shared/icons/reload-to-stop.svg
new file mode 100644
index 000000000000..b58501447b18
--- /dev/null
+++ b/browser/themes/shared/icons/reload-to-stop.svg
@@ -0,0 +1,1550 @@
+
diff --git a/browser/themes/shared/icons/stop-to-reload.svg b/browser/themes/shared/icons/stop-to-reload.svg
new file mode 100644
index 000000000000..26dfbb75eeab
--- /dev/null
+++ b/browser/themes/shared/icons/stop-to-reload.svg
@@ -0,0 +1,1298 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/themes/shared/jar.inc.mn b/browser/themes/shared/jar.inc.mn
index 476ec15fa297..b8c9736d5b31 100644
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -164,12 +164,14 @@
skin/classic/browser/privateBrowsing.svg (../shared/icons/privateBrowsing.svg)
skin/classic/browser/quit.svg (../shared/icons/quit.svg)
skin/classic/browser/reload.svg (../shared/icons/reload.svg)
+ skin/classic/browser/reload-to-stop.svg (../shared/icons/reload-to-stop.svg)
skin/classic/browser/save.svg (../shared/icons/save.svg)
skin/classic/browser/settings.svg (../shared/icons/settings.svg)
skin/classic/browser/share.svg (../shared/icons/share.svg)
skin/classic/browser/sidebars.svg (../shared/icons/sidebars.svg)
skin/classic/browser/sidebars-right.svg (../shared/icons/sidebars-right.svg)
skin/classic/browser/stop.svg (../shared/icons/stop.svg)
+ skin/classic/browser/stop-to-reload.svg (../shared/icons/stop-to-reload.svg)
skin/classic/browser/sync.svg (../shared/icons/sync.svg)
skin/classic/browser/synced-tabs.svg (../shared/icons/synced-tabs.svg)
skin/classic/browser/webIDE.svg (../shared/icons/webIDE.svg)
diff --git a/browser/themes/shared/toolbarbutton-icons.inc.css b/browser/themes/shared/toolbarbutton-icons.inc.css
index 6c9cb7052030..122125c9ad48 100644
--- a/browser/themes/shared/toolbarbutton-icons.inc.css
+++ b/browser/themes/shared/toolbarbutton-icons.inc.css
@@ -36,6 +36,120 @@ toolbar[brighttext] :-moz-any(@primaryToolbarButtons@) {
}
%ifdef MOZ_PHOTON_THEME
+%ifdef MOZ_PHOTON_ANIMATIONS
+#stop-reload-button[animate] > #reload-button > .toolbarbutton-icon,
+#stop-reload-button[animate] > #reload-button[displaystop] + #stop-button > .toolbarbutton-icon {
+ fill: transparent;
+}
+
+@keyframes reload-to-stop {
+ from {
+ transform: translateX(0);
+ }
+ to {
+ transform: translateX(-738px);
+ }
+}
+
+@keyframes reload-to-stop-rtl {
+ from {
+ transform: scaleX(-1) translateX(0);
+ }
+ to {
+ transform: scaleX(-1) translateX(-738px);
+ }
+}
+
+@keyframes stop-to-reload {
+ from {
+ transform: translateX(0);
+ }
+ to {
+ transform: translateX(-612px);
+ }
+}
+
+@keyframes stop-to-reload-rtl {
+ from {
+ transform: scaleX(-1) translateX(0);
+ }
+ to {
+ transform: scaleX(-1) translateX(-612px);
+ }
+}
+
+#reload-button > .toolbarbutton-animatable-box,
+#stop-button > .toolbarbutton-animatable-box {
+ position: fixed;
+ overflow: hidden;
+ margin-top: -10px; /* Vertically center the 20px tall animatable image */
+ /* Since .toolbarbutton-icon uses a different width than the animatable-box,
+ we need to set a padding relative to the difference in widths. */
+ margin-inline-start: calc((16px + 2 * var(--toolbarbutton-inner-padding) - 18px) / 2);
+ width: 18px; /* Width of each frame within the SVG sprite */
+ height: 20px; /* Height of each frame within the SVG sprite */
+}
+
+#reload-button > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image,
+#stop-button > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
+ height: 20px; /* Height of each frame within the SVG sprite */
+ animation-fill-mode: forwards;
+ animation-iteration-count: 1;
+ list-style-image: none;
+}
+
+#stop-reload-button[animate] > #reload-button > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
+ background-image: url("chrome://browser/skin/reload-to-stop.svg");
+ width: 756px;
+}
+
+#stop-reload-button[animate] > #reload-button:not([displaystop]) > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
+ animation-name: reload-to-stop;
+}
+
+#stop-reload-button[animate] > #reload-button:not([displaystop]):-moz-locale-dir(rtl) > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
+ animation-name: reload-to-stop-rtl;
+}
+
+#reload-button:not([displaystop]) > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
+ animation-timing-function: steps(41);
+ animation-duration: 684ms;
+}
+
+#stop-reload-button[animate] > #reload-button[displaystop] + #stop-button > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
+ background-image: url("chrome://browser/skin/stop-to-reload.svg");
+ width: 630px;
+}
+
+#stop-reload-button[animate] > #reload-button[displaystop] + #stop-button > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
+ animation-name: stop-to-reload;
+}
+
+#stop-reload-button[animate] > #reload-button[displaystop] + #stop-button:-moz-locale-dir(rtl) > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
+ animation-name: stop-to-reload-rtl;
+}
+
+#reload-button[displaystop] + #stop-button > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
+ animation-timing-function: steps(34);
+ animation-duration: 600ms;
+}
+
+#reload-button > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
+ transform: translateX(-738px);
+}
+
+#reload-button:-moz-locale-dir(rtl) > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
+ transform: scaleX(-1) translateX(-738px);
+}
+
+#reload-button[displaystop] + #stop-button > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
+ transform: translateX(-612px);
+}
+
+#reload-button[displaystop] + #stop-button:-moz-locale-dir(rtl) > .toolbarbutton-animatable-box > .toolbarbutton-animatable-image {
+ transform: scaleX(-1) translateX(-612px);
+}
+%endif
#reload-button {
list-style-image: url("chrome://browser/skin/reload.svg");
}