Bug 947854 part 1 - Use CSS transition instead of JS animation for hiding toolbox in fullscreen mode and simplify related code. r=dao
authorXidorn Quan <quanxunzhen@gmail.com>
Wed, 06 May 2015 10:04:31 +1200
changeset 242489 f1cd052c7fb76258b2bf6a9a7a04e206697875ce
parent 242488 373a497c69ca735e9054793c215e97abe54db61b
child 242490 4ac24fe93a883797e5439cbcc7cb9a07f6617e4a
push id28697
push usercbook@mozilla.com
push dateWed, 06 May 2015 09:59:51 +0000
treeherdermozilla-central@60349cbc3d4e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdao
bugs947854
milestone40.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
Bug 947854 part 1 - Use CSS transition instead of JS animation for hiding toolbox in fullscreen mode and simplify related code. r=dao
browser/base/content/browser-fullScreen.js
browser/base/content/browser.css
browser/base/content/browser.js
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -65,28 +65,24 @@ var FullScreen = {
 
     // show/hide menubars, toolbars (except the full screen toolbar)
     this.showXULChrome("toolbar", !enterFS);
 
     if (enterFS) {
       document.addEventListener("keypress", this._keyToggleCallback, false);
       document.addEventListener("popupshown", this._setPopupOpen, false);
       document.addEventListener("popuphidden", this._setPopupOpen, false);
+      this._shouldAnimate = true;
       // We don't animate the toolbar collapse if in DOM full-screen mode,
       // as the size of the content area would still be changing after the
       // mozfullscreenchange event fired, which could confuse content script.
-      this._shouldAnimate = !document.mozFullScreen;
-      this.mouseoverToggle(false);
+      this.hideNavToolbox(document.mozFullScreen);
     }
     else {
-      // The user may quit fullscreen during an animation
-      this._cancelAnimation();
-      gNavToolbox.style.marginTop = "";
-      if (this._isChromeCollapsed)
-        this.mouseoverToggle(true);
+      this.showNavToolbox(false);
       // This is needed if they use the context menu to quit fullscreen
       this._isPopupOpen = false;
 
       document.documentElement.removeAttribute("inDOMFullscreen");
 
       this.cleanup();
     }
   },
@@ -167,18 +163,17 @@ var FullScreen = {
     // If a fullscreen window loses focus, we show a warning when the
     // fullscreen window is refocused.
     if (!this.useLionFullScreen) {
       window.addEventListener("activate", this);
     }
 
     // Cancel any "hide the toolbar" animation which is in progress, and make
     // the toolbar hide immediately.
-    this._cancelAnimation();
-    this.mouseoverToggle(false);
+    this.hideNavToolbox(true);
   },
 
   cleanup: function () {
     if (window.fullScreen) {
       MousePosTracker.removeListener(this);
       document.removeEventListener("keypress", this._keyToggleCallback, false);
       document.removeEventListener("popupshown", this._setPopupOpen, false);
       document.removeEventListener("popuphidden", this._setPopupOpen, false);
@@ -198,33 +193,32 @@ var FullScreen = {
   getMouseTargetRect: function()
   {
     return this._mouseTargetRect;
   },
 
   // Event callbacks
   _expandCallback: function()
   {
-    FullScreen.mouseoverToggle(true);
+    FullScreen.showNavToolbox();
   },
   onMouseEnter: function()
   {
-    FullScreen.mouseoverToggle(false);
+    FullScreen.hideNavToolbox();
   },
   _keyToggleCallback: function(aEvent)
   {
     // if we can use the keyboard (eg Ctrl+L or Ctrl+E) to open the toolbars, we
     // should provide a way to collapse them too.
     if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) {
-      FullScreen._shouldAnimate = false;
-      FullScreen.mouseoverToggle(false, true);
+      FullScreen.hideNavToolbox(true);
     }
     // F6 is another shortcut to the address bar, but its not covered in OpenLocation()
     else if (aEvent.keyCode == aEvent.DOM_VK_F6)
-      FullScreen.mouseoverToggle(true);
+      FullScreen.showNavToolbox();
   },
 
   // Checks whether we are allowed to collapse the chrome
   _isPopupOpen: false,
   _isChromeCollapsed: false,
   _safeToCollapse: function(forceHide)
   {
     if (!gPrefService.getBoolPref("browser.fullscreen.autohide"))
@@ -268,57 +262,16 @@ var FullScreen = {
   },
   setAutohide: function()
   {
     gPrefService.setBoolPref("browser.fullscreen.autohide", !gPrefService.getBoolPref("browser.fullscreen.autohide"));
   },
 
   // Animate the toolbars disappearing
   _shouldAnimate: true,
-  _isAnimating: false,
-  _animationTimeout: 0,
-  _animationHandle: 0,
-  _animateUp: function() {
-    // check again, the user may have done something before the animation was due to start
-    if (!window.fullScreen || !this._safeToCollapse(false)) {
-      this._isAnimating = false;
-      this._shouldAnimate = true;
-      return;
-    }
-
-    this._animateStartTime = window.mozAnimationStartTime;
-    if (!this._animationHandle)
-      this._animationHandle = window.mozRequestAnimationFrame(this);
-  },
-
-  sample: function (timeStamp) {
-    const duration = 1500;
-    const timePassed = timeStamp - this._animateStartTime;
-    const pos = timePassed >= duration ? 1 :
-                1 - Math.pow(1 - timePassed / duration, 4);
-
-    if (pos >= 1) {
-      // We've animated enough
-      this._cancelAnimation();
-      gNavToolbox.style.marginTop = "";
-      this.mouseoverToggle(false);
-      return;
-    }
-
-    gNavToolbox.style.marginTop = (gNavToolbox.boxObject.height * pos * -1) + "px";
-    this._animationHandle = window.mozRequestAnimationFrame(this);
-  },
-
-  _cancelAnimation: function() {
-    window.mozCancelAnimationFrame(this._animationHandle);
-    this._animationHandle = 0;
-    clearTimeout(this._animationTimeout);
-    this._isAnimating = false;
-    this._shouldAnimate = false;
-  },
 
   cancelWarning: function(event) {
     if (!this.warningBox)
       return;
     this.warningBox.removeEventListener("transitionend", this);
     if (this.warningFadeOutTimeout) {
       clearTimeout(this.warningFadeOutTimeout);
       this.warningFadeOutTimeout = null;
@@ -465,63 +418,79 @@ var FullScreen = {
         setTimeout(
           function() {
             if (this.warningBox)
               this.warningBox.setAttribute("fade-warning-out", "true");
           }.bind(this),
           3000);
   },
 
-  mouseoverToggle: function(aShow, forceHide)
-  {
-    // Don't do anything if:
-    // a) we're already in the state we want,
-    // b) we're animating and will become collapsed soon, or
-    // c) we can't collapse because it would be undesirable right now
-    if (aShow != this._isChromeCollapsed || (!aShow && this._isAnimating) ||
-        (!aShow && !this._safeToCollapse(forceHide)))
-      return;
+  showNavToolbox: function(trackMouse = true) {
+    this._fullScrToggler.hidden = true;
+    gNavToolbox.removeAttribute("fullscreenShouldAnimate");
+    gNavToolbox.style.marginTop = "";
 
-    // browser.fullscreen.animateUp
-    // 0 - never animate up
-    // 1 - animate only for first collapse after entering fullscreen (default for perf's sake)
-    // 2 - animate every time it collapses
-    if (gPrefService.getIntPref("browser.fullscreen.animateUp") == 0)
-      this._shouldAnimate = false;
-
-    if (!aShow && this._shouldAnimate) {
-      this._isAnimating = true;
-      this._shouldAnimate = false;
-      this._animationTimeout = setTimeout(this._animateUp.bind(this), 800);
+    if (!this._isChromeCollapsed) {
       return;
     }
 
-    // Hiding/collapsing the toolbox interferes with the tab bar's scrollbox,
-    // so we just move it off-screen instead. See bug 430687.
-    gNavToolbox.style.marginTop =
-      aShow ? "" : -gNavToolbox.getBoundingClientRect().height + "px";
-
-    this._fullScrToggler.hidden = aShow || document.mozFullScreen;
-
-    if (aShow) {
+    // Track whether mouse is near the toolbox
+    this._isChromeCollapsed = false;
+    if (trackMouse) {
       let rect = gBrowser.mPanelContainer.getBoundingClientRect();
       this._mouseTargetRect = {
         top: rect.top + 50,
         bottom: rect.bottom,
         left: rect.left,
         right: rect.right
       };
       MousePosTracker.addListener(this);
-    } else {
-      MousePosTracker.removeListener(this);
+    }
+  },
+
+  hideNavToolbox: function(forceHide = false) {
+    this._fullScrToggler.hidden = document.mozFullScreen;
+    if (this._isChromeCollapsed) {
+      if (forceHide) {
+        gNavToolbox.removeAttribute("fullscreenShouldAnimate");
+      }
+      return;
+    }
+    if (!this._safeToCollapse(forceHide)) {
+      this._fullScrToggler.hidden = true;
+      return;
     }
 
-    this._isChromeCollapsed = !aShow;
-    if (gPrefService.getIntPref("browser.fullscreen.animateUp") == 2)
+    // browser.fullscreen.animateUp
+    // 0 - never animate up
+    // 1 - animate only for first collapse after entering fullscreen (default for perf's sake)
+    // 2 - animate every time it collapses
+    let animateUp = gPrefService.getIntPref("browser.fullscreen.animateUp");
+    if (animateUp == 0) {
+      this._shouldAnimate = false;
+    } else if (animateUp == 2) {
       this._shouldAnimate = true;
+    }
+    if (this._shouldAnimate && !forceHide) {
+      gNavToolbox.setAttribute("fullscreenShouldAnimate", true);
+      this._shouldAnimate = false;
+      // Hide the fullscreen toggler until the transition ends.
+      let listener = () => {
+        gNavToolbox.removeEventListener("transitionend", listener, true);
+        if (this._isChromeCollapsed)
+          this._fullScrToggler.hidden = false;
+      };
+      gNavToolbox.addEventListener("transitionend", listener, true);
+      this._fullScrToggler.hidden = true;
+    }
+
+    gNavToolbox.style.marginTop =
+      -gNavToolbox.getBoundingClientRect().height + "px";
+    this._isChromeCollapsed = true;
+    MousePosTracker.removeListener(this);
   },
 
   showXULChrome: function(aTag, aShow)
   {
     var els = document.getElementsByTagNameNS(this._XULNS, aTag);
 
     for (let el of els) {
       // XXX don't interfere with previously collapsed toolbars
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -295,16 +295,20 @@ toolbar[customizing] > .overflow-button 
   visibility: collapse;
 }
 
 #main-window[inFullscreen] #global-notificationbox,
 #main-window[inFullscreen] #high-priority-global-notificationbox {
   visibility: collapse;
 }
 
+#navigator-toolbox[fullscreenShouldAnimate] {
+  transition: 1.5s margin-top ease-out;
+}
+
 /* Rules to help integrate SDK widgets */
 toolbaritem[sdkstylewidget="true"] > toolbarbutton,
 toolbarpaletteitem > toolbaritem[sdkstylewidget="true"] > iframe,
 toolbarpaletteitem > toolbaritem[sdkstylewidget="true"] > .toolbarbutton-text {
   display: none;
 }
 
 toolbarpaletteitem:-moz-any([place="palette"], [place="panel"]) > toolbaritem[sdkstylewidget="true"] > toolbarbutton {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1949,17 +1949,17 @@ function loadOneOrMoreURIs(aURIString)
   }
   catch (e) {
   }
 }
 
 function focusAndSelectUrlBar() {
   if (gURLBar) {
     if (window.fullScreen)
-      FullScreen.mouseoverToggle(true);
+      FullScreen.showNavToolbox();
 
     gURLBar.select();
     if (document.activeElement == gURLBar.inputField)
       return true;
   }
   return false;
 }
 
@@ -3412,17 +3412,17 @@ const BrowserSearch = {
       let navBar = document.getElementById(CustomizableUI.AREA_NAVBAR);
       navBar.overflowable.show().then(() => {
         focusSearchBar();
       });
       return;
     }
     if (searchBar) {
       if (window.fullScreen)
-        FullScreen.mouseoverToggle(true);
+        FullScreen.showNavToolbox();
       searchBar.select();
     }
     openSearchPageIfFieldIsNotActive(searchBar);
   },
 
   /**
    * Loads a search results page, given a set of search terms. Uses the current
    * engine if the search bar is visible, or the default engine otherwise.