Bug 707956 - Restore original zoom scale on double rotation. r=kats
authorPatrick Walton <pwalton@mozilla.com>
Fri, 20 Jan 2012 21:14:03 -0800
changeset 86282 0e9d30f46b7d4957f76d3be8815e728a9f163c97
parent 86281 f1b3f874e000b373ec052e6800e13fcb8578a6c1
child 86283 ca4e2ab3717c92fa039096bb042978d570d9c7f4
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs707956
milestone12.0a1
Bug 707956 - Restore original zoom scale on double rotation. r=kats
mobile/android/base/gfx/LayerController.java
mobile/android/base/gfx/ViewportMetrics.java
mobile/android/chrome/content/browser.js
--- a/mobile/android/base/gfx/LayerController.java
+++ b/mobile/android/base/gfx/LayerController.java
@@ -162,17 +162,26 @@ public class LayerController {
      * The view calls this function to indicate that the viewport changed size. It must hold the
      * monitor while calling it.
      *
      * TODO: Refactor this to use an interface. Expose that interface only to the view and not
      * to the layer client. That way, the layer client won't be tempted to call this, which might
      * result in an infinite loop.
      */
     public void setViewportSize(FloatSize size) {
+        // Resize the viewport, and modify its zoom factor so that the page retains proportionally
+        // zoomed relative to the screen.
+        float oldWidth = mViewportMetrics.getSize().width;
+        float oldZoomFactor = mViewportMetrics.getZoomFactor();
         mViewportMetrics.setSize(size);
+
+        PointF newFocus = new PointF(size.width / 2.0f, size.height / 2.0f);
+        float newZoomFactor = size.width * oldZoomFactor / oldWidth;
+        mViewportMetrics.scaleTo(newZoomFactor, newFocus);
+
         Log.d(LOGTAG, "setViewportSize: " + mViewportMetrics);
         setForceRedraw();
 
         if (mLayerClient != null)
             mLayerClient.viewportSizeChanged();
 
         notifyLayerClientOfGeometryChange();
         mPanZoomController.abortAnimation();
--- a/mobile/android/base/gfx/ViewportMetrics.java
+++ b/mobile/android/base/gfx/ViewportMetrics.java
@@ -274,21 +274,26 @@ public class ViewportMetrics {
     public boolean fuzzyEquals(ViewportMetrics other) {
         return mPageSize.fuzzyEquals(other.mPageSize)
             && RectUtils.fuzzyEquals(mViewportRect, other.mViewportRect)
             && FloatUtils.fuzzyEquals(mViewportOffset, other.mViewportOffset)
             && FloatUtils.fuzzyEquals(mZoomFactor, other.mZoomFactor);
     }
 
     public String toJSON() {
+        // Round off height and width. Since the height and width are the size of the screen, it
+        // makes no sense to send non-integer coordinates to Gecko.
+        int height = Math.round(mViewportRect.height());
+        int width = Math.round(mViewportRect.width());
+
         StringBuffer sb = new StringBuffer(256);
         sb.append("{ \"x\" : ").append(mViewportRect.left)
           .append(", \"y\" : ").append(mViewportRect.top)
-          .append(", \"width\" : ").append(mViewportRect.width())
-          .append(", \"height\" : ").append(mViewportRect.height())
+          .append(", \"width\" : ").append(width)
+          .append(", \"height\" : ").append(height)
           .append(", \"pageWidth\" : ").append(mPageSize.width)
           .append(", \"pageHeight\" : ").append(mPageSize.height)
           .append(", \"offsetX\" : ").append(mViewportOffset.x)
           .append(", \"offsetY\" : ").append(mViewportOffset.y)
           .append(", \"zoom\" : ").append(mZoomFactor)
           .append(" }");
         return sb.toString();
     }
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -1564,19 +1564,22 @@ Tab.prototype = {
         this._viewport.pageWidth = pageWidth;
         this._viewport.pageHeight = pageHeight;
       }
     }
 
     return this._viewport;
   },
 
-  updateViewport: function(aReset) {
+  updateViewport: function(aReset, aZoomLevel) {
+    if (!aZoomLevel)
+      aZoomLevel = this.getDefaultZoomLevel();
+
     let win = this.browser.contentWindow;
-    let zoom = (aReset ? this.getDefaultZoomLevel() : this._viewport.zoom);
+    let zoom = (aReset ? aZoomLevel : this._viewport.zoom);
     let xpos = ((aReset && win) ? win.scrollX * zoom : this._viewport.x);
     let ypos = ((aReset && win) ? win.scrollY * zoom : this._viewport.y);
 
     this.viewportExcess = { x: 0, y: 0 };
     this.viewport = { x: xpos, y: ypos,
                       offsetX: 0, offsetY: 0,
                       width: this._viewport.width, height: this._viewport.height,
                       pageWidth: gScreenWidth, pageHeight: gScreenHeight,
@@ -1944,17 +1947,33 @@ Tab.prototype = {
         viewportH = viewportW * (screenH / screenW);
     }
 
     // Make sure the viewport height is not shorter than the window when
     // the page is zoomed out to show its full width.
     let minScale = this.getPageZoomLevel(screenW);
     viewportH = Math.max(viewportH, screenH / minScale);
 
+    let oldBrowserWidth = parseInt(this.browser.style.width);
     this.setBrowserSize(viewportW, viewportH);
+
+    // Avoid having the scroll position jump around after device rotation.
+    let win = this.browser.contentWindow;
+    this.userScrollPos.x = win.scrollX;
+    this.userScrollPos.y = win.scrollY;
+
+    // If the browser width changes, we change the zoom proportionally. This ensures sensible
+    // behavior when rotating the device on pages with automatically-resizing viewports.
+
+    if (viewportW == oldBrowserWidth)
+      return;
+
+    let viewport = this.viewport;
+    let newZoom = oldBrowserWidth * viewport.zoom / viewportW;
+    this.updateViewport(true, newZoom);
   },
 
   getDefaultZoomLevel: function getDefaultZoomLevel() {
     let md = this.metadata;
     if ("defaultZoom" in md && md.defaultZoom)
       return md.defaultZoom;
 
     let browserWidth = parseInt(this.browser.style.width);