Commit 48761699 authored by Florian Quèze's avatar Florian Quèze
Browse files

Bug 1391704 - Avoid flickering while moving tabs across windows, r=mconley.

parent 0c9a3b08
Loading
Loading
Loading
Loading
+21 −33
Original line number Diff line number Diff line
@@ -1379,6 +1379,25 @@ var gBrowserInit = {

    gRemoteControl.updateVisualCue(Marionette.running);

    // If we are given a tab to swap in, take care of it before first paint to
    // avoid an about:blank flash.
    let tabToOpen = window.arguments && window.arguments[0];
    if (tabToOpen instanceof XULElement) {
      // Clear the reference to the tab from the arguments array.
      window.arguments[0] = null;

      // Stop the about:blank load
      gBrowser.stop();
      // make sure it has a docshell
      gBrowser.docShell;

      try {
        gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToOpen);
      } catch (e) {
        Cu.reportError(e);
      }
    }

    // Wait until chrome is painted before executing code not critical to making the window visible
    this._boundDelayedStartup = this._delayedStartup.bind(this);
    window.addEventListener("MozAfterPaint", this._boundDelayedStartup);
@@ -1605,6 +1624,8 @@ var gBrowserInit = {
        return;
      }

      // We don't check if uriToLoad is a XULElement because this case has
      // already been handled before first paint, and the argument cleared.
      if (uriToLoad instanceof Ci.nsIArray) {
        let count = uriToLoad.length;
        let specs = [];
@@ -1622,39 +1643,6 @@ var gBrowserInit = {
            triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
          });
        } catch (e) {}
      } else if (uriToLoad instanceof XULElement) {
        // swap the given tab with the default about:blank tab and then close
        // the original tab in the other window.
        let tabToOpen = uriToLoad;

        // If this tab was passed as a window argument, clear the
        // reference to it from the arguments array.
        if (window.arguments[0] == tabToOpen) {
          window.arguments[0] = null;
        }

        // Stop the about:blank load
        gBrowser.stop();
        // make sure it has a docshell
        gBrowser.docShell;

        // We must set usercontextid before updateBrowserRemoteness()
        // so that the newly created remote tab child has correct usercontextid
        if (tabToOpen.hasAttribute("usercontextid")) {
          let usercontextid = tabToOpen.getAttribute("usercontextid");
          gBrowser.selectedBrowser.setAttribute("usercontextid", usercontextid);
        }

        try {
          // Make sure selectedBrowser has the same remote settings as the one
          // we are swapping in.
          gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser,
                                           tabToOpen.linkedBrowser.isRemoteBrowser,
                                           { remoteType: tabToOpen.linkedBrowser.remoteType });
          gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToOpen);
        } catch (e) {
          Cu.reportError(e);
        }
      } else if (window.arguments.length >= 3) {
        // window.arguments[2]: referrer (nsIURI | string)
        //                 [3]: postData (nsIInputStream)
+45 −4
Original line number Diff line number Diff line
@@ -3009,6 +3009,16 @@

              newTab = true;
            }
            aTab._endRemoveArgs = [closeWindow, newTab];

            // swapBrowsersAndCloseOther will take care of closing the window without animation.
            if (closeWindow && aAdoptedByTab) {
              // Remove the tab's filter to avoid leaking.
              if (aTab.linkedPanel) {
                this._tabFilters.delete(aTab);
              }
              return true;
            }

            if (!aTab._fullyOpen) {
              // If the opening tab animation hasn't finished before we start closing the
@@ -3079,7 +3089,6 @@
                tab.owner = null;
            }

            aTab._endRemoveArgs = [closeWindow, newTab];
            return true;
          ]]>
        </body>
@@ -3297,6 +3306,25 @@
            if (!remoteBrowser._beginRemoveTab(aOtherTab, aOurTab, true))
              return;

            // If this is the last tab of the window, hide the window
            // immediately without animation before the docshell swap, to avoid
            // about:blank being painted.
            let [closeWindow] = aOtherTab._endRemoveArgs;
            if (closeWindow) {
              let win = aOtherTab.ownerGlobal;
              let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor)
                           .getInterface(Ci.nsIDOMWindowUtils);
              dwu.suppressAnimation(true);
              // Only suppressing window animations isn't enough to avoid
              // an empty content area being painted.
              let baseWin = win.QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIDocShell)
                               .QueryInterface(Ci.nsIDocShellTreeItem)
                               .treeOwner
                               .QueryInterface(Ci.nsIBaseWindow);
              baseWin.visibility = false;
            }

            let modifiedAttrs = [];
            if (aOtherTab.hasAttribute("muted")) {
              aOurTab.setAttribute("muted", "true");
@@ -3363,7 +3391,11 @@
            }

            // Finish tearing down the tab that's going away.
            if (closeWindow) {
              aOtherTab.ownerGlobal.close();
            } else {
              remoteBrowser._endRemoveTab(aOtherTab);
            }

            this.setTabTitle(aOurTab);

@@ -3729,6 +3761,14 @@
            for (var name in aOptions)
              options += "," + name + "=" + aOptions[name];

            // Play the tab closing animation to give immediate feedback while
            // waiting for the new window to appear.
            // content area when the docshells are swapped.
            if (this.animationsEnabled) {
              aTab.style.maxWidth = ""; // ensure that fade-out transition happens
              aTab.removeAttribute("fadein");
            }

            // tell a new window to take the "dropped" tab
            return window.openDialog(getBrowserURL(), "_blank", options, aTab);
          ]]>
@@ -3851,7 +3891,8 @@
          let linkedBrowser = aTab.linkedBrowser;
          let params = { eventDetail: { adoptedTab: aTab },
                         preferredRemoteType: linkedBrowser.remoteType,
                         sameProcessAsFrameLoader: linkedBrowser.frameLoader };
                         sameProcessAsFrameLoader: linkedBrowser.frameLoader,
                         skipAnimation: true };
          if (aTab.hasAttribute("usercontextid")) {
            // new tab must have the same usercontextid as the old one
            params.userContextId = aTab.getAttribute("usercontextid");
@@ -7407,7 +7448,7 @@
          window.moveTo(left, top);
          window.focus();
        } else {
          let props = { screenX: left, screenY: top };
          let props = { screenX: left, screenY: top, suppressanimation: 1 };
          if (AppConstants.platform != "win") {
            props.outerWidth = winWidth;
            props.outerHeight = winHeight;
+5 −5
Original line number Diff line number Diff line
@@ -318,15 +318,15 @@ const PanelUI = {
   *
   * @return a Promise that resolves once the panel is ready to roll.
   */
  ensureReady() {
    if (this._readyPromise) {
      return this._readyPromise;
  async ensureReady() {
    if (this._isReady) {
      return;
    }

    await window.delayedStartupPromise;
    this._ensureEventListenersAdded();
    this.panel.hidden = false;
    this._readyPromise = Promise.resolve();
    this._isReady = true;
    return this._readyPromise;
  },

  /**
+2 −1
Original line number Diff line number Diff line
@@ -26,8 +26,9 @@ add_task(function* () {
  // Detach the tab with RDM open.
  let newWindow = gBrowser.replaceTabWithWindow(tab);

  // Waiting the tab is detached.
  // Wait until the tab is detached and the new window is fully initialized.
  yield waitTabIsDetached;
  yield newWindow.delayedStartupPromise;

  // Get the new tab instance.
  tab = newWindow.gBrowser.tabs[0];
+1 −1
Original line number Diff line number Diff line
@@ -69,7 +69,7 @@ add_task(async function test_swap_frameloader_pagevisibility_events() {

  // We have to wait for the window to load so we can get the selected browser
  // to listen to.
  await BrowserTestUtils.waitForEvent(newWindow, "load");
  await BrowserTestUtils.waitForEvent(newWindow, "DOMContentLoaded");
  let newWindowBrowser = newWindow.gBrowser.selectedBrowser;

  // Wait for the expected pagehide and pageshow events on the initial browser