Bug 860493: Add arrow indicators for history swipes on macOS. r=felipe,bram
authorStephen A Pohl <spohl.mozilla.bugs@gmail.com>
Wed, 16 May 2018 23:09:39 -0400
changeset 418594 5a43d47a768cbfc844eb9fb20c51bff9f840c69c
parent 418593 46f0e465153ff635684aafa645d3a326d6534316
child 418595 59cc6b99727e58e3b214266c45089d945999c285
push id103344
push userspohl@mozilla.com
push dateThu, 17 May 2018 03:10:17 +0000
treeherdermozilla-inbound@c95d5c9994e8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfelipe, bram
bugs860493
milestone62.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 860493: Add arrow indicators for history swipes on macOS. r=felipe,bram
browser/base/content/browser-gestureSupport.js
browser/base/content/browser.css
browser/base/content/history-swipe-arrow.svg
browser/base/jar.mn
browser/themes/osx/browser.css
browser/themes/osx/jar.mn
browser/themes/osx/subtle-pattern.png
--- a/browser/base/content/browser-gestureSupport.js
+++ b/browser/base/content/browser-gestureSupport.js
@@ -231,17 +231,17 @@ var gGestureSupport = {
    * gesture, if enabled.
    *
    * @param aEvent
    *        The swipe gesture start event.
    * @return true if swipe gestures could successfully be set up, false
    *         othwerwise.
    */
   _setupSwipeGesture: function GS__setupSwipeGesture() {
-    gHistorySwipeAnimation.startAnimation(false);
+    gHistorySwipeAnimation.startAnimation();
 
     this._doUpdate = function GS__doUpdate(aEvent) {
       gHistorySwipeAnimation.updateAnimation(aEvent.delta);
     };
 
     this._doEnd = function GS__doEnd(aEvent) {
       gHistorySwipeAnimation.swipeEndEventReceived();
 
@@ -400,22 +400,18 @@ var gGestureSupport = {
    *
    * @param aEvent
    *        The swipe event to handle
    * @param aDir
    *        The direction for the swipe event
    */
   _coordinateSwipeEventWithAnimation:
   function GS__coordinateSwipeEventWithAnimation(aEvent, aDir) {
-    if ((gHistorySwipeAnimation.isAnimationRunning()) &&
-        (aDir == "RIGHT" || aDir == "LEFT")) {
-      gHistorySwipeAnimation.processSwipeEvent(aEvent, aDir);
-    } else {
-      this.processSwipeEvent(aEvent, aDir);
-    }
+    gHistorySwipeAnimation.stopAnimation();
+    this.processSwipeEvent(aEvent, aDir);
   },
 
   /**
    * Get a gesture preference or use a default if it doesn't exist
    *
    * @param aPref
    *        Name of the preference to load under the gesture branch
    * @param aDef
@@ -579,358 +575,188 @@ var gHistorySwipeAnimation = {
   active: false,
   isLTR: false,
 
   /**
    * Initializes the support for history swipe animations, if it is supported
    * by the platform/configuration.
    */
   init: function HSA_init() {
-    if (!this._isSupported())
+    if (!this._isSupported()) {
       return;
+    }
 
-    this.active = false;
     this.isLTR = document.documentElement.matches(":-moz-locale-dir(ltr)");
-    this._trackedSnapshots = [];
-    this._startingIndex = -1;
-    this._historyIndex = -1;
-    this._boxWidth = -1;
-    this._boxHeight = -1;
-    this._maxSnapshots = this._getMaxSnapshots();
-    this._lastSwipeDir = "";
-    this._direction = "horizontal";
-
-    // We only want to activate history swipe animations if we store snapshots.
-    // If we don't store any, we handle horizontal swipes without animations.
-    if (this._maxSnapshots > 0) {
-      this.active = true;
-      gBrowser.addEventListener("pagehide", this);
-      gBrowser.addEventListener("pageshow", this);
-      gBrowser.addEventListener("popstate", this);
-      gBrowser.addEventListener("DOMModalDialogClosed", this);
-      gBrowser.tabContainer.addEventListener("TabClose", this);
-    }
+    this._isStoppingAnimation = false;
+    this.active = true;
   },
 
   /**
    * Uninitializes the support for history swipe animations.
    */
   uninit: function HSA_uninit() {
-    gBrowser.removeEventListener("pagehide", this);
-    gBrowser.removeEventListener("pageshow", this);
-    gBrowser.removeEventListener("popstate", this);
-    gBrowser.removeEventListener("DOMModalDialogClosed", this);
-    gBrowser.tabContainer.removeEventListener("TabClose", this);
-
     this.active = false;
     this.isLTR = false;
+    this._removeBoxes();
   },
 
   /**
-   * Starts the swipe animation and handles fast swiping (i.e. a swipe animation
-   * is already in progress when a new one is initiated).
+   * Starts the swipe animation.
    *
    * @param aIsVerticalSwipe
    *        Whether we're dealing with a vertical swipe or not.
    */
-  startAnimation: function HSA_startAnimation(aIsVerticalSwipe) {
-    this._direction = aIsVerticalSwipe ? "vertical" : "horizontal";
-
+  startAnimation: function HSA_startAnimation() {
     if (this.isAnimationRunning()) {
-      // If this is a horizontal scroll, or if this is a vertical scroll that
-      // was started while a horizontal scroll was still running, handle it as
-      // as a fast swipe. In the case of the latter scenario, this allows us to
-      // start the vertical animation without first loading the final page, or
-      // taking another snapshot. If vertical scrolls are initiated repeatedly
-      // without prior horizontal scroll we skip this and restart the animation
-      // from 0.
-      if (this._direction == "horizontal" || this._lastSwipeDir != "") {
-        gBrowser.stop();
-        this._lastSwipeDir = "RELOAD"; // just ensure that != ""
-        this._canGoBack = this.canGoBack();
-        this._canGoForward = this.canGoForward();
-        this._handleFastSwiping();
-      }
-      this.updateAnimation(0);
-    } else {
-      // Get the session history from SessionStore.
-      let updateSessionHistory = sessionHistory => {
-        this._startingIndex = sessionHistory.index;
-        this._historyIndex = this._startingIndex;
-        this._canGoBack = this.canGoBack();
-        this._canGoForward = this.canGoForward();
-        if (this.active) {
-          this._addBoxes();
-          this._takeSnapshot();
-          this._installPrevAndNextSnapshots();
-          this._lastSwipeDir = "";
-        }
-        this.updateAnimation(0);
-      };
-      SessionStore.getSessionHistory(gBrowser.selectedTab, updateSessionHistory);
+      return;
     }
+
+    this._isStoppingAnimation = false;
+    this._canGoBack = this.canGoBack();
+    this._canGoForward = this.canGoForward();
+    if (this.active) {
+      this._addBoxes();
+    }
+    this.updateAnimation(0);
   },
 
   /**
    * Stops the swipe animation.
    */
   stopAnimation: function HSA_stopAnimation() {
-    gHistorySwipeAnimation._removeBoxes();
-    this._historyIndex = this._getCurrentHistoryIndex();
+    if (!this.isAnimationRunning()) {
+      return;
+    }
+    this._isStoppingAnimation = true;
+    let box = this._prevBox.style.opacity > 0 ? this._prevBox : this._nextBox;
+    if (box.style.opacity > 0) {
+      box.style.transition = "opacity 0.2s cubic-bezier(.07,.95,0,1)";
+      box.addEventListener("transitionend", this._completeFadeOut);
+      box.style.opacity = 0;
+    } else {
+      this._removeBoxes();
+    }
   },
 
   /**
    * Updates the animation between two pages in history.
    *
    * @param aVal
    *        A floating point value that represents the progress of the
    *        swipe gesture.
    */
   updateAnimation: function HSA_updateAnimation(aVal) {
-    if (!this.isAnimationRunning()) {
+    if (!this.isAnimationRunning() || this._isStoppingAnimation) {
       return;
     }
 
-    // We use the following value to decrease the bounce effect when scrolling
-    // to the top or bottom of the page, or when swiping back/forward past the
-    // browsing history. This value was determined experimentally.
-    let dampValue = 4;
-    if (this._direction == "vertical") {
-      this._prevBox.collapsed = true;
-      this._nextBox.collapsed = true;
-      this._positionBox(this._curBox, -1 * aVal / dampValue);
-    } else if ((aVal >= 0 && this.isLTR) ||
-               (aVal <= 0 && !this.isLTR)) {
-      let tempDampValue = 1;
+    // We use the following value to set the opacity of the swipe arrows. It was
+    // determined experimentally that absolute values of 0.25 (or greater)
+    // trigger history navigation, hence the multiplier 4 to set the arrows to
+    // full opacity at 0.25 or greater.
+    let opacity = Math.abs(aVal) * 4;
+    if ((aVal >= 0 && this.isLTR) ||
+        (aVal <= 0 && !this.isLTR)) {
+      // The intention is to go back.
       if (this._canGoBack) {
         this._prevBox.collapsed = false;
-      } else {
-        tempDampValue = dampValue;
-        this._prevBox.collapsed = true;
+        this._nextBox.collapsed = true;
+        this._prevBox.style.opacity = opacity > 1 ? 1 : opacity;
       }
-
-      // The current page is pushed to the right (LTR) or left (RTL),
-      // the intention is to go back.
-      // If there is a page to go back to, it should show in the background.
-      this._positionBox(this._curBox, aVal / tempDampValue);
-
-      // The forward page should be pushed offscreen all the way to the right.
-      this._positionBox(this._nextBox, 1);
     } else if (this._canGoForward) {
-      // The intention is to go forward. If there is a page to go forward to,
-      // it should slide in from the right (LTR) or left (RTL).
-      // Otherwise, the current page should slide to the left (LTR) or
-      // right (RTL) and the backdrop should appear in the background.
-      // For the backdrop to be visible in that case, the previous page needs
-      // to be hidden (if it exists).
+      // The intention is to go forward.
       this._nextBox.collapsed = false;
-      let offset = this.isLTR ? 1 : -1;
-      this._positionBox(this._curBox, 0);
-      this._positionBox(this._nextBox, offset + aVal);
-    } else {
       this._prevBox.collapsed = true;
-      this._positionBox(this._curBox, aVal / dampValue);
-    }
-  },
-
-  _getCurrentHistoryIndex() {
-    return SessionStore.getSessionHistory(gBrowser.selectedTab).index;
-  },
-
-  /**
-   * Event handler for events relevant to the history swipe animation.
-   *
-   * @param aEvent
-   *        An event to process.
-   */
-  handleEvent: function HSA_handleEvent(aEvent) {
-    let browser = gBrowser.selectedBrowser;
-    switch (aEvent.type) {
-      case "TabClose":
-        let browserForTab = gBrowser.getBrowserForTab(aEvent.target);
-        this._removeTrackedSnapshot(-1, browserForTab);
-        break;
-      case "DOMModalDialogClosed":
-        this.stopAnimation();
-        break;
-      case "pageshow":
-        if (aEvent.target == browser.contentDocument) {
-          this.stopAnimation();
-        }
-        break;
-      case "popstate":
-        if (aEvent.target == browser.contentDocument.defaultView) {
-          this.stopAnimation();
-        }
-        break;
-      case "pagehide":
-        if (aEvent.target == browser.contentDocument) {
-          // Take and compress a snapshot of a page whenever it's about to be
-          // navigated away from. We already have a snapshot of the page if an
-          // animation is running, so we're left with compressing it.
-          if (!this.isAnimationRunning()) {
-            this._takeSnapshot();
-          }
-          this._compressSnapshotAtCurrentIndex();
-        }
-        break;
+      this._nextBox.style.opacity = opacity > 1 ? 1 : opacity;
     }
   },
 
   /**
    * Checks whether the history swipe animation is currently running or not.
    *
    * @return true if the animation is currently running, false otherwise.
    */
   isAnimationRunning: function HSA_isAnimationRunning() {
     return !!this._container;
   },
 
   /**
-   * Process a swipe event based on the given direction.
-   *
-   * @param aEvent
-   *        The swipe event to handle
-   * @param aDir
-   *        The direction for the swipe event
-   */
-  processSwipeEvent: function HSA_processSwipeEvent(aEvent, aDir) {
-    if (aDir == "RIGHT")
-      this._historyIndex += this.isLTR ? 1 : -1;
-    else if (aDir == "LEFT")
-      this._historyIndex += this.isLTR ? -1 : 1;
-    else
-      return;
-    this._lastSwipeDir = aDir;
-  },
-
-  /**
    * Checks if there is a page in the browser history to go back to.
    *
    * @return true if there is a previous page in history, false otherwise.
    */
   canGoBack: function HSA_canGoBack() {
-    if (this.isAnimationRunning())
-      return this._doesIndexExistInHistory(this._historyIndex - 1);
     return gBrowser.webNavigation.canGoBack;
   },
 
   /**
    * Checks if there is a page in the browser history to go forward to.
    *
    * @return true if there is a next page in history, false otherwise.
    */
   canGoForward: function HSA_canGoForward() {
-    if (this.isAnimationRunning())
-      return this._doesIndexExistInHistory(this._historyIndex + 1);
     return gBrowser.webNavigation.canGoForward;
   },
 
   /**
    * Used to notify the history swipe animation that the OS sent a swipe end
    * event and that we should navigate to the page that the user swiped to, if
    * any. This will also result in the animation overlay to be torn down.
    */
   swipeEndEventReceived: function HSA_swipeEndEventReceived() {
-    // Update the session history before continuing.
-    let updateSessionHistory = sessionHistory => {
-      if (this._lastSwipeDir != "" && this._historyIndex != this._startingIndex)
-        this._navigateToHistoryIndex();
-      else
-        this.stopAnimation();
-    };
-    SessionStore.getSessionHistory(gBrowser.selectedTab, updateSessionHistory);
-  },
-
-  /**
-   * Checks whether a particular index exists in the browser history or not.
-   *
-   * @param aIndex
-   *        The index to check for availability for in the history.
-   * @return true if the index exists in the browser history, false otherwise.
-   */
-  _doesIndexExistInHistory: function HSA__doesIndexExistInHistory(aIndex) {
-    try {
-      return SessionStore.getSessionHistory(gBrowser.selectedTab).entries[aIndex] != null;
-    } catch (ex) {
-      return false;
-    }
-  },
-
-  /**
-   * Navigates to the index in history that is currently being tracked by
-   * |this|.
-   */
-  _navigateToHistoryIndex: function HSA__navigateToHistoryIndex() {
-    if (this._doesIndexExistInHistory(this._historyIndex))
-      gBrowser.webNavigation.gotoIndex(this._historyIndex);
-    else
-      this.stopAnimation();
+    this.stopAnimation();
   },
 
   /**
    * Checks to see if history swipe animations are supported by this
    * platform/configuration.
    *
    * return true if supported, false otherwise.
    */
   _isSupported: function HSA__isSupported() {
     return window.matchMedia("(-moz-swipe-animation-enabled)").matches;
   },
 
-  /**
-   * Handle fast swiping (i.e. a swipe animation is already in
-   * progress when a new one is initiated). This will swap out the snapshots
-   * used in the previous animation with the appropriate new ones.
-   */
-  _handleFastSwiping: function HSA__handleFastSwiping() {
-    this._installCurrentPageSnapshot(null);
-    this._installPrevAndNextSnapshots();
+  _completeFadeOut: function HSA__completeFadeOut(aEvent) {
+    gHistorySwipeAnimation._removeBoxes();
   },
 
   /**
-   * Adds the boxes that contain the snapshots used during the swipe animation.
+   * Adds the boxes that contain the arrows used during the swipe animation.
    */
   _addBoxes: function HSA__addBoxes() {
     let browserStack =
       document.getAnonymousElementByAttribute(gBrowser.getNotificationBox(),
                                               "class", "browserStack");
     this._container = this._createElement("historySwipeAnimationContainer",
                                           "stack");
     browserStack.appendChild(this._container);
 
-    this._prevBox = this._createElement("historySwipeAnimationPreviousPage",
+    this._prevBox = this._createElement("historySwipeAnimationPreviousArrow",
                                         "box");
+    this._prevBox.collapsed = true;
+    this._prevBox.style.opacity = 0;
     this._container.appendChild(this._prevBox);
 
-    this._curBox = this._createElement("historySwipeAnimationCurrentPage",
-                                       "box");
-    this._container.appendChild(this._curBox);
-
-    this._nextBox = this._createElement("historySwipeAnimationNextPage",
+    this._nextBox = this._createElement("historySwipeAnimationNextArrow",
                                         "box");
+    this._nextBox.collapsed = true;
+    this._nextBox.style.opacity = 0;
     this._container.appendChild(this._nextBox);
-
-    // Cache width and height.
-    this._boxWidth = this._curBox.getBoundingClientRect().width;
-    this._boxHeight = this._curBox.getBoundingClientRect().height;
   },
 
   /**
    * Removes the boxes.
    */
   _removeBoxes: function HSA__removeBoxes() {
-    this._curBox = null;
     this._prevBox = null;
     this._nextBox = null;
     if (this._container)
       this._container.remove();
     this._container = null;
-    this._boxWidth = -1;
-    this._boxHeight = -1;
   },
 
   /**
    * Creates an element with a given identifier and tag name.
    *
    * @param aID
    *        An identifier to create the element with.
    * @param aTagName
@@ -938,305 +764,9 @@ var gHistorySwipeAnimation = {
    * @return the newly created element.
    */
   _createElement: function HSA__createElement(aID, aTagName) {
     let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
     let element = document.createElementNS(XULNS, aTagName);
     element.id = aID;
     return element;
   },
-
-  /**
-   * Moves a given box to a given X coordinate position.
-   *
-   * @param aBox
-   *        The box element to position.
-   * @param aPosition
-   *        The position (in X coordinates) to move the box element to.
-   */
-  _positionBox: function HSA__positionBox(aBox, aPosition) {
-    let transform = "";
-
-    if (this._direction == "vertical")
-      transform = "translateY(" + this._boxHeight * aPosition + "px)";
-    else
-      transform = "translateX(" + this._boxWidth * aPosition + "px)";
-
-    aBox.style.transform = transform;
-  },
-
-  /**
-   * Verifies that we're ready to take snapshots based on the global pref and
-   * the current index in history.
-   *
-   * @return true if we're ready to take snapshots, false otherwise.
-   */
-  _readyToTakeSnapshots: function HSA__readyToTakeSnapshots() {
-    return (this._maxSnapshots >= 1 && this._getCurrentHistoryIndex() >= 0);
-  },
-
-  /**
-   * Takes a snapshot of the page the browser is currently on.
-   */
-  _takeSnapshot: function HSA__takeSnapshot() {
-    if (!this._readyToTakeSnapshots()) {
-      return;
-    }
-
-    let canvas = null;
-
-    let browser = gBrowser.selectedBrowser;
-    let r = browser.getBoundingClientRect();
-    canvas = document.createElementNS("http://www.w3.org/1999/xhtml",
-                                      "canvas");
-    canvas.mozOpaque = true;
-    let scale = window.devicePixelRatio;
-    canvas.width = r.width * scale;
-    canvas.height = r.height * scale;
-    let ctx = canvas.getContext("2d");
-    let zoom = browser.markupDocumentViewer.fullZoom * scale;
-    ctx.scale(zoom, zoom);
-    ctx.drawWindow(browser.contentWindow,
-                   0, 0, canvas.width / zoom, canvas.height / zoom, "white",
-                   ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_VIEW |
-                   ctx.DRAWWINDOW_ASYNC_DECODE_IMAGES |
-                   ctx.DRAWWINDOW_USE_WIDGET_LAYERS);
-
-    TelemetryStopwatch.start("FX_GESTURE_INSTALL_SNAPSHOT_OF_PAGE");
-    try {
-      this._installCurrentPageSnapshot(canvas);
-      this._assignSnapshotToCurrentBrowser(canvas);
-    } finally {
-      TelemetryStopwatch.finish("FX_GESTURE_INSTALL_SNAPSHOT_OF_PAGE");
-    }
-  },
-
-  /**
-   * Retrieves the maximum number of snapshots that should be kept in memory.
-   * This limit is a global limit and is valid across all open tabs.
-   */
-  _getMaxSnapshots: function HSA__getMaxSnapshots() {
-    return Services.prefs.getIntPref("browser.snapshots.limit");
-  },
-
-  /**
-   * Adds a snapshot to the list and initiates the compression of said snapshot.
-   * Once the compression is completed, it will replace the uncompressed
-   * snapshot in the list.
-   *
-   * @param aCanvas
-   *        The snapshot to add to the list and compress.
-   */
-  _assignSnapshotToCurrentBrowser:
-  function HSA__assignSnapshotToCurrentBrowser(aCanvas) {
-    let browser = gBrowser.selectedBrowser;
-    let currIndex = this._getCurrentHistoryIndex();
-
-    this._removeTrackedSnapshot(currIndex, browser);
-    this._addSnapshotRefToArray(currIndex, browser);
-
-    if (!("snapshots" in browser))
-      browser.snapshots = [];
-    let snapshots = browser.snapshots;
-    // Temporarily store the canvas as the compressed snapshot.
-    // This avoids a blank page if the user swipes quickly
-    // between pages before the compression could complete.
-    snapshots[currIndex] = {
-      image: aCanvas,
-      scale: window.devicePixelRatio
-    };
-  },
-
-  /**
-   * Compresses the HTMLCanvasElement that's stored at the current history
-   * index in the snapshot array and stores the compressed image in its place.
-   */
-  _compressSnapshotAtCurrentIndex:
-  function HSA__compressSnapshotAtCurrentIndex() {
-    if (!this._readyToTakeSnapshots()) {
-      // We didn't take a snapshot earlier because we weren't ready to, so
-      // there's nothing to compress.
-      return;
-    }
-
-    TelemetryStopwatch.start("FX_GESTURE_COMPRESS_SNAPSHOT_OF_PAGE");
-    try {
-      let browser = gBrowser.selectedBrowser;
-      let snapshots = browser.snapshots;
-      let currIndex = this._getCurrentHistoryIndex();
-
-      // Kick off snapshot compression.
-      let canvas = snapshots[currIndex].image;
-      canvas.toBlob(function(aBlob) {
-          if (snapshots[currIndex]) {
-            snapshots[currIndex].image = aBlob;
-          }
-        }, "image/png"
-      );
-    } finally {
-      TelemetryStopwatch.finish("FX_GESTURE_COMPRESS_SNAPSHOT_OF_PAGE");
-    }
-  },
-
-  /**
-   * Removes a snapshot identified by the browser and index in the array of
-   * snapshots for that browser, if present. If no snapshot could be identified
-   * the method simply returns without taking any action. If aIndex is negative,
-   * all snapshots for a particular browser will be removed.
-   *
-   * @param aIndex
-   *        The index in history of the new snapshot, or negative value if all
-   *        snapshots for a browser should be removed.
-   * @param aBrowser
-   *        The browser the new snapshot was taken in.
-   */
-  _removeTrackedSnapshot: function HSA__removeTrackedSnapshot(aIndex, aBrowser) {
-    let arr = this._trackedSnapshots;
-    let requiresExactIndexMatch = aIndex >= 0;
-    for (let i = 0; i < arr.length; i++) {
-      if ((arr[i].browser == aBrowser) &&
-          (aIndex < 0 || aIndex == arr[i].index)) {
-        delete aBrowser.snapshots[arr[i].index];
-        arr.splice(i, 1);
-        if (requiresExactIndexMatch)
-          return; // Found and removed the only element.
-        i--; // Make sure to revisit the index that we just removed an
-             // element at.
-      }
-    }
-  },
-
-  /**
-   * Adds a new snapshot reference for a given index and browser to the array
-   * of references to tracked snapshots.
-   *
-   * @param aIndex
-   *        The index in history of the new snapshot.
-   * @param aBrowser
-   *        The browser the new snapshot was taken in.
-   */
-  _addSnapshotRefToArray:
-  function HSA__addSnapshotRefToArray(aIndex, aBrowser) {
-    let id = { index: aIndex,
-               browser: aBrowser };
-    let arr = this._trackedSnapshots;
-    arr.unshift(id);
-
-    while (arr.length > this._maxSnapshots) {
-      let lastElem = arr[arr.length - 1];
-      delete lastElem.browser.snapshots[lastElem.index].image;
-      delete lastElem.browser.snapshots[lastElem.index];
-      arr.splice(-1, 1);
-    }
-  },
-
-  /**
-   * Converts a compressed blob to an Image object. In some situations
-   * (especially during fast swiping) aBlob may still be a canvas, not a
-   * compressed blob. In this case, we simply return the canvas.
-   *
-   * @param aBlob
-   *        The compressed blob to convert, or a canvas if a blob compression
-   *        couldn't complete before this method was called.
-   * @return A new Image object representing the converted blob.
-   */
-  _convertToImg: function HSA__convertToImg(aBlob) {
-    if (!aBlob)
-      return null;
-
-    // Return aBlob if it's still a canvas and not a compressed blob yet.
-    if (aBlob instanceof HTMLCanvasElement)
-      return aBlob;
-
-    let img = new Image();
-    let url = "";
-    try {
-      url = URL.createObjectURL(aBlob);
-      img.onload = function() {
-        URL.revokeObjectURL(url);
-      };
-    } finally {
-      img.src = url;
-    }
-    return img;
-  },
-
-  /**
-   * Scales the background of a given box element (which uses a given snapshot
-   * as background) based on a given scale factor.
-   * @param aSnapshot
-   *        The snapshot that is used as background of aBox.
-   * @param aScale
-   *        The scale factor to use.
-   * @param aBox
-   *        The box element that uses aSnapshot as background.
-   */
-  _scaleSnapshot: function HSA__scaleSnapshot(aSnapshot, aScale, aBox) {
-    if (aSnapshot && aScale != 1 && aBox) {
-      if (aSnapshot instanceof HTMLCanvasElement) {
-        aBox.style.backgroundSize =
-          aSnapshot.width / aScale + "px " + aSnapshot.height / aScale + "px";
-      } else {
-        // snapshot is instanceof HTMLImageElement
-        aSnapshot.addEventListener("load", function() {
-          aBox.style.backgroundSize =
-            aSnapshot.width / aScale + "px " + aSnapshot.height / aScale + "px";
-        });
-      }
-    }
-  },
-
-  /**
-   * Sets the snapshot of the current page to the snapshot passed as parameter,
-   * or to the one previously stored for the current index in history if the
-   * parameter is null.
-   *
-   * @param aCanvas
-   *        The snapshot to set the current page to. If this parameter is null,
-   *        the previously stored snapshot for this index (if any) will be used.
-   */
-  _installCurrentPageSnapshot:
-  function HSA__installCurrentPageSnapshot(aCanvas) {
-    let currSnapshot = aCanvas;
-    let scale = window.devicePixelRatio;
-    if (!currSnapshot) {
-      let snapshots = gBrowser.selectedBrowser.snapshots || {};
-      let currIndex = this._historyIndex;
-      if (currIndex in snapshots) {
-        currSnapshot = this._convertToImg(snapshots[currIndex].image);
-        scale = snapshots[currIndex].scale;
-      }
-    }
-    this._scaleSnapshot(currSnapshot, scale, this._curBox ? this._curBox :
-                                                            null);
-    document.mozSetImageElement("historySwipeAnimationCurrentPageSnapshot",
-                                currSnapshot);
-  },
-
-  /**
-   * Sets the snapshots of the previous and next pages to the snapshots
-   * previously stored for their respective indeces.
-   */
-  _installPrevAndNextSnapshots:
-  function HSA__installPrevAndNextSnapshots() {
-    let snapshots = gBrowser.selectedBrowser.snapshots || [];
-    let currIndex = this._historyIndex;
-    let prevIndex = currIndex - 1;
-    let prevSnapshot = null;
-    if (prevIndex in snapshots) {
-      prevSnapshot = this._convertToImg(snapshots[prevIndex].image);
-      this._scaleSnapshot(prevSnapshot, snapshots[prevIndex].scale,
-                          this._prevBox);
-    }
-    document.mozSetImageElement("historySwipeAnimationPreviousPageSnapshot",
-                                prevSnapshot);
-
-    let nextIndex = currIndex + 1;
-    let nextSnapshot = null;
-    if (nextIndex in snapshots) {
-      nextSnapshot = this._convertToImg(snapshots[nextIndex].image);
-      this._scaleSnapshot(nextSnapshot, snapshots[nextIndex].scale,
-                          this._nextBox);
-    }
-    document.mozSetImageElement("historySwipeAnimationNextPageSnapshot",
-                                nextSnapshot);
-  },
 };
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -882,34 +882,27 @@ window[chromehidden~="toolbar"] toolbar:
 #mainPopupSet {
   min-width: 1px;
 }
 
 /* History Swipe Animation */
 
 #historySwipeAnimationContainer {
   overflow: hidden;
-}
-
-#historySwipeAnimationPreviousPage,
-#historySwipeAnimationCurrentPage,
-#historySwipeAnimationNextPage {
-  background: none top left no-repeat white;
+  pointer-events: none;
 }
 
-#historySwipeAnimationPreviousPage {
-  background-image: -moz-element(#historySwipeAnimationPreviousPageSnapshot);
+#historySwipeAnimationPreviousArrow {
+  background: url("chrome://browser/content/history-swipe-arrow.svg")
+              center left / 64px 128px no-repeat transparent;
 }
-
-#historySwipeAnimationCurrentPage {
-  background-image: -moz-element(#historySwipeAnimationCurrentPageSnapshot);
-}
-
-#historySwipeAnimationNextPage {
-  background-image: -moz-element(#historySwipeAnimationNextPageSnapshot);
+#historySwipeAnimationNextArrow {
+  background: url("chrome://browser/content/history-swipe-arrow.svg")
+              center left / 64px 128px no-repeat transparent;
+  transform: rotate(180deg);
 }
 
 /*  Full Screen UI */
 
 #fullscr-toggler {
   height: 1px;
   background: black;
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/history-swipe-arrow.svg
@@ -0,0 +1,4 @@
+<svg width="256" height="512" xmlns="http://www.w3.org/2000/svg">
+  <ellipse ry="256" rx="256" cy="256" cx="0" stroke-width="0" stroke="#000" fill="#38383d"/>
+  <path d="m181.335236,247.749695l-96.549957,0l35.774963,-35.774994a8.33333,8.33333 0 0 0 -11.783325,-11.783325l-49.999969,49.999954a8.33333,8.33333 0 0 0 0,11.782944l49.999969,50a8.33333,8.33333 0 0 0 11.783325,-11.783325l-35.774963,-35.774994l96.549957,0a8.33333,8.33333 0 0 0 0,-16.66626z" fill="rgba(249, 249, 250, .8)"/>
+</svg>
\ No newline at end of file
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -91,16 +91,17 @@ browser.jar:
         content/browser/defaultthemes/4.header.png    (content/defaultthemes/4.header.png)
         content/browser/defaultthemes/4.icon.png      (content/defaultthemes/4.icon.png)
         content/browser/defaultthemes/4.preview.png   (content/defaultthemes/4.preview.png)
         content/browser/defaultthemes/5.header.png    (content/defaultthemes/5.header.png)
         content/browser/defaultthemes/5.icon.jpg      (content/defaultthemes/5.icon.jpg)
         content/browser/defaultthemes/5.preview.jpg   (content/defaultthemes/5.preview.jpg)
         content/browser/defaultthemes/dark.icon.svg   (content/defaultthemes/dark.icon.svg)
         content/browser/defaultthemes/light.icon.svg  (content/defaultthemes/light.icon.svg)
+        content/browser/history-swipe-arrow.svg       (content/history-swipe-arrow.svg)
 *       content/browser/pageinfo/pageInfo.xul         (content/pageinfo/pageInfo.xul)
         content/browser/pageinfo/pageInfo.js          (content/pageinfo/pageInfo.js)
         content/browser/pageinfo/pageInfo.css         (content/pageinfo/pageInfo.css)
         content/browser/pageinfo/feeds.js             (content/pageinfo/feeds.js)
         content/browser/pageinfo/permissions.js       (content/pageinfo/permissions.js)
         content/browser/pageinfo/security.js          (content/pageinfo/security.js)
         content/browser/robot.ico                     (content/robot.ico)
         content/browser/static-robot.png              (content/static-robot.png)
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -633,28 +633,16 @@ html|input.urlbar-input {
   opacity: 1.0;
   color: #bbb;
 }
 
 .editBMPanel_rowLabel {
   text-align: end;
 }
 
-/* History Swipe Animation */
-
-#historySwipeAnimationCurrentPage,
-#historySwipeAnimationNextPage {
-  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.6);
-}
-
-#historySwipeAnimationContainer {
-  background: url("chrome://browser/skin/subtle-pattern.png") #B3B9C1;
-}
-
-
 /* ----- SIDEBAR ELEMENTS ----- */
 
 %include ../shared/sidebar.inc.css
 
 #sidebar-box {
   -moz-appearance: -moz-mac-source-list;
   -moz-font-smoothing-background-color: -moz-mac-source-list;
   /* Default font size is 11px on mac, so this is 12px */
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -4,17 +4,16 @@
 
 browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
 #include ../shared/jar.inc.mn
   skin/classic/browser/sanitizeDialog.css
 * skin/classic/browser/syncedtabs/sidebar.css          (syncedtabs/sidebar.css)
 * skin/classic/browser/browser.css
 * skin/classic/browser/compacttheme.css
-  skin/classic/browser/subtle-pattern.png
   skin/classic/browser/panel-expander-closed.png
   skin/classic/browser/panel-expander-closed@2x.png
   skin/classic/browser/panel-expander-open.png
   skin/classic/browser/panel-expander-open@2x.png
   skin/classic/browser/panel-plus-sign.png
   skin/classic/browser/page-livemarks.png
 * skin/classic/browser/pageInfo.css
 * skin/classic/browser/searchbar.css
deleted file mode 100644
index f0597b6a151c2dc73515799387e720dec49483a5..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001