allow animated zooming to continue seemlessly if animation is already in progress
authorBenjamin Stover <bstover@mozilla.com>
Thu, 02 Sep 2010 16:49:14 -0700
changeset 66631 f1ba58a10f57f8c7e362c86ad749ebb65741a6d9
parent 66630 2ec5396338c04603f72bab7a9088b5b69e2ac078
child 66632 0a00ed3b1ac92eb29fd5d3ce1c98326af98d7065
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
allow animated zooming to continue seemlessly if animation is already in progress
mobile/chrome/content/AnimatedZoom.js
mobile/chrome/content/browser.js
--- a/mobile/chrome/content/AnimatedZoom.js
+++ b/mobile/chrome/content/AnimatedZoom.js
@@ -41,38 +41,73 @@
 
 let Cc = Components.classes;
 let Ci = Components.interfaces;
 let Cu = Components.utils;
 
 /**
  * Responsible for zooming in to a given view rectangle
  */
-function AnimatedZoom() {
-  // Render a snapshot of the viewport contents around the visible rect
-  this.animationDuration = Services.prefs.getIntPref("browser.ui.zoom.animationDuration");
-}
+const animatedZoom = {
+  /** Starts an animated zoom to zoomRect. */
+  animateTo: function(aZoomRect) {
+    if (!aZoomRect)
+      return;
+
+    this.zoomTo = aZoomRect.clone();
+
+    if (this.animationDuration === undefined)
+      this.animationDuration = Services.prefs.getIntPref("browser.ui.zoom.animationDuration");
 
-AnimatedZoom.prototype = {
-  startTimer: function() {
-    if (this.zoomTo && !this.beginTime) {
-      Browser.hideSidebars();
-      Browser.hideTitlebar();
-      Browser.forceChromeReflow();
+    Browser.hideSidebars();
+    Browser.hideTitlebar();
+    Browser.forceChromeReflow();
+
+    this.beginTime = Date.now();
 
+    // Check if zooming animations were occuring before.
+    if (this.zoomFrom) {
+      this.zoomFrom = this.zoomRect;
+    }
+    else {
       let browserRect = Rect.fromRect(getBrowser().getBoundingClientRect());
-      this.zoomFrom = browserRect.translate(getBrowser()._frameLoader.viewportScrollX, getBrowser()._frameLoader.viewportScrollY);
+      let scrollX = {}, scrollY = {};
+      getBrowser().getPosition(scrollX, scrollY);
+      this.zoomFrom = browserRect.translate(scrollX.value, scrollY.value);
+      this.updateTo(this.zoomFrom);
 
-      this.updateTo(this.zoomFrom);
-      this.beginTime = Date.now();
       window.addEventListener("MozBeforePaint", this, false);
       mozRequestAnimationFrame();
     }
   },
 
+  /** Updates the zoom to new rect. */
+  updateTo: function(nextRect) {
+    let zoomRatio = window.innerWidth / nextRect.width;
+    let zoomLevel = getBrowser().scale * zoomRatio;
+    // XXX using the underlying frameLoader APIs is undesirable and is not a
+    // pattern to propagate. The browser binding should be taking care of this!
+    // There is some bug that I have not yet discovered that make browser.scrollTo
+    // not behave correctly and there is no intelligence in browser.scale to keep
+    // the actual resolution changes small.
+    getBrowser()._frameLoader.setViewportScale(zoomLevel, zoomLevel);
+    getBrowser()._frameLoader.scrollViewportTo(nextRect.left * zoomRatio, nextRect.top * zoomRatio);
+    this.zoomRect = nextRect;
+  },
+
+  /** Stop animation, zoom to point, and clean up. */
+  finish: function() {
+    window.removeEventListener("MozBeforePaint", this, false);
+    Browser.setVisibleRect(this.zoomTo);
+    this.beginTime = null;
+    this.zoomTo = null;
+    this.zoomFrom = null;
+    this.zoomRect = null;
+  },
+
   handleEvent: function(aEvent) {
     try {
       let tdiff = aEvent.timeStamp - this.beginTime;
       let counter = tdiff / this.animationDuration;
       if (counter < 1) {
         // update browser to interpolated rectangle
         let rect = this.zoomFrom.blend(this.zoomTo, Math.min(counter, 1));
         this.updateTo(rect);
@@ -82,37 +117,10 @@ AnimatedZoom.prototype = {
         // last cycle already rendered final scaled image, now clean up
         this.finish();
       }
     }
     catch(e) {
       this.finish();
       throw e;
     }
-  },
-
-  /** Updates the zoom to new rect. */
-  updateTo: function(nextRect) {
-    let zoomRatio = window.innerWidth / nextRect.width;
-    let zoomLevel = getBrowser().scale * zoomRatio;
-    // XXX using the underlying frameLoader APIs is undesirable and is not a
-    // pattern to propagate. The browser binding should be taking care of this!
-    // There is some bug that I have not yet discovered that make browser.scrollTo
-    // not behave correctly and there is no intelligence in browser.scale to keep
-    // the actual resolution changes small.
-    getBrowser()._frameLoader.setViewportScale(zoomLevel, zoomLevel);
-    getBrowser()._frameLoader.scrollViewportTo(nextRect.left * zoomRatio, nextRect.top * zoomRatio);
-  },
-
-  /** Starts an animated zoom to zoomRect. */
-  animateTo: function(aZoomRect) {
-    this.zoomTo = aZoomRect.clone();
-    this.startTimer();
-  },
-
-  /** Stop animation, zoom to point, and clean up. */
-  finish: function() {
-    window.removeEventListener("MozBeforePaint", this, false);
-    Browser.setVisibleRect(this.zoomTo);
-    this.beginTime = null;
-    this.zoomTo = null;
   }
 };
--- a/mobile/chrome/content/browser.js
+++ b/mobile/chrome/content/browser.js
@@ -906,18 +906,17 @@ var Browser = {
     let newVisW = window.innerWidth / zoomRatio, newVisH = window.innerHeight / zoomRatio;
     let result = new Rect(x - newVisW / 2, y - newVisH / 2, newVisW, newVisH);
 
     // Make sure rectangle doesn't poke out of viewport
     return result.translateInside(new Rect(0, 0, getBrowser()._widthInDevicePx, getBrowser()._heightInDevicePx));
   },
 
   animatedZoomTo: function animatedZoomTo(rect) {
-    let zoom = new AnimatedZoom();
-    zoom.animateTo(rect);
+    animatedZoom.animateTo(rect);
   },
 
   setVisibleRect: function setVisibleRect(rect) {
     let zoomRatio = window.innerWidth / rect.width;
     let zoomLevel = getBrowser().scale * zoomRatio;
     let scrollX = rect.left * zoomRatio;
     let scrollY = rect.top * zoomRatio;