Bug 709152 - Adjust viewport offset while panning. r=pcwalton
authorChris Lord <chrislord.net@gmail.com>
Thu, 22 Dec 2011 11:35:41 +0000
changeset 83253 f75ee6fa2587786a28716c62896f33c198ffaecc
parent 83252 943ac1d43ad4799bd83d155929ed1c76d4e7b9e0
child 83254 65f3838752d8df85d52974369ddf36ff0c2944ac
push id21744
push userbmo@edmorley.co.uk
push dateFri, 23 Dec 2011 23:56:40 +0000
treeherdermozilla-central@ede336ccaed0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspcwalton
bugs709152
milestone12.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 709152 - Adjust viewport offset while panning. r=pcwalton This patch adjusts the viewport offset while panning to increase the buffered area in the direction of panning, and thereby reduce checkerboarding.
mobile/android/base/gfx/GeckoSoftwareLayerClient.java
mobile/android/base/gfx/ViewportMetrics.java
--- a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java
+++ b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java
@@ -302,17 +302,16 @@ public class GeckoSoftwareLayerClient ex
             mPendingViewportAdjust = true;
             return;
         }
 
         adjustViewport();
     }
 
     private void adjustViewport() {
-        Log.i(LOGTAG, "Adjusting viewport");
         ViewportMetrics viewportMetrics =
             new ViewportMetrics(getLayerController().getViewportMetrics());
 
         PointF viewportOffset = viewportMetrics.getOptimumViewportOffset(mBufferSize);
         viewportMetrics.setViewportOffset(viewportOffset);
         viewportMetrics.setViewport(viewportMetrics.getClampedViewport());
 
         GeckoAppShell.sendEventToGecko(new GeckoEvent(viewportMetrics));
--- a/mobile/android/base/gfx/ViewportMetrics.java
+++ b/mobile/android/base/gfx/ViewportMetrics.java
@@ -59,29 +59,36 @@ import android.util.Log;
 public class ViewportMetrics {
     private static final String LOGTAG = "GeckoViewportMetrics";
 
     private FloatSize mPageSize;
     private RectF mViewportRect;
     private PointF mViewportOffset;
     private float mZoomFactor;
 
+    // A scale from -1,-1 to 1,1 that represents what edge of the displayport
+    // we want the viewport to be biased towards.
+    private PointF mViewportBias;
+    private static final float MAX_BIAS = 0.8f;
+
     public ViewportMetrics() {
         mPageSize = new FloatSize(1, 1);
         mViewportRect = new RectF(0, 0, 1, 1);
         mViewportOffset = new PointF(0, 0);
         mZoomFactor = 1.0f;
+        mViewportBias = new PointF(0.0f, 0.0f);
     }
 
     public ViewportMetrics(ViewportMetrics viewport) {
         mPageSize = new FloatSize(viewport.getPageSize());
         mViewportRect = new RectF(viewport.getViewport());
         PointF offset = viewport.getViewportOffset();
         mViewportOffset = new PointF(offset.x, offset.y);
         mZoomFactor = viewport.getZoomFactor();
+        mViewportBias = viewport.mViewportBias;
     }
 
     public ViewportMetrics(JSONObject json) throws JSONException {
         float x = (float)json.getDouble("x");
         float y = (float)json.getDouble("y");
         float width = (float)json.getDouble("width");
         float height = (float)json.getDouble("height");
         float pageWidth = (float)json.getDouble("pageWidth");
@@ -89,46 +96,46 @@ public class ViewportMetrics {
         float offsetX = (float)json.getDouble("offsetX");
         float offsetY = (float)json.getDouble("offsetY");
         float zoom = (float)json.getDouble("zoom");
 
         mPageSize = new FloatSize(pageWidth, pageHeight);
         mViewportRect = new RectF(x, y, x + width, y + height);
         mViewportOffset = new PointF(offsetX, offsetY);
         mZoomFactor = zoom;
+        mViewportBias = new PointF(0.0f, 0.0f);
     }
 
     public PointF getOptimumViewportOffset(IntSize displayportSize) {
-        // XXX We currently always position the viewport in the centre of the
-        //     displayport, but we might want to optimise this during panning
-        //     to minimise checkerboarding.
-        Point optimumOffset =
-            new Point((int)Math.round((displayportSize.width - mViewportRect.width()) / 2),
-                      (int)Math.round((displayportSize.height - mViewportRect.height()) / 2));
+        /* XXX Until bug #524925 is fixed, changing the viewport origin will
+         *     cause unnecessary relayouts. This may cause rendering time to
+         *     increase and should be considered.
+         */
+        RectF viewport = getClampedViewport();
 
-        /* XXX Until bug #524925 is fixed, changing the viewport origin will
-         * probably cause things to be slower than just having a smaller usable
-         * displayport.
-         */
-        Rect viewport = RectUtils.round(getClampedViewport());
+        FloatSize bufferSpace = new FloatSize(displayportSize.width - viewport.width(),
+                                            displayportSize.height - viewport.height());
+        PointF optimumOffset =
+            new PointF(bufferSpace.width * ((mViewportBias.x + 1.0f) / 2.0f),
+                       bufferSpace.height * ((mViewportBias.y + 1.0f) / 2.0f));
 
         // Make sure this offset won't cause wasted pixels in the displayport
         // (i.e. make sure the resultant displayport intersects with the page
         //  as much as possible)
         if (viewport.left - optimumOffset.x < 0)
           optimumOffset.x = viewport.left;
-        else if (optimumOffset.x + viewport.right > mPageSize.width)
-          optimumOffset.x -= (mPageSize.width - (optimumOffset.x + viewport.right));
+        else if ((bufferSpace.width - optimumOffset.x) + viewport.right > mPageSize.width)
+          optimumOffset.x = bufferSpace.width - (mPageSize.width - viewport.right);
 
         if (viewport.top - optimumOffset.y < 0)
           optimumOffset.y = viewport.top;
-        else if (optimumOffset.y + viewport.bottom > mPageSize.height)
-          optimumOffset.y -= (mPageSize.height - (optimumOffset.y + viewport.bottom));
+        else if ((bufferSpace.height - optimumOffset.y) + viewport.bottom > mPageSize.height)
+          optimumOffset.y = bufferSpace.height - (mPageSize.height - viewport.bottom);
 
-        return new PointF(optimumOffset);
+        return new PointF(Math.round(optimumOffset.x), Math.round(optimumOffset.y));
     }
 
     public PointF getOrigin() {
         return new PointF(mViewportRect.left, mViewportRect.top);
     }
 
     public PointF getDisplayportOrigin() {
         return new PointF(mViewportRect.left - mViewportOffset.x,
@@ -179,16 +186,33 @@ public class ViewportMetrics {
         mPageSize = pageSize;
     }
 
     public void setViewport(RectF viewport) {
         mViewportRect = viewport;
     }
 
     public void setOrigin(PointF origin) {
+        // When the origin is set, we compare it with the last value set and
+        // change the viewport bias accordingly, so that any viewport based
+        // on these metrics will have a larger buffer in the direction of
+        // movement.
+
+        // XXX Note the comment about bug #524925 in getOptimumViewportOffset.
+        //     Ideally, the viewport bias would be a sliding scale, but we
+        //     don't want to change it too often at the moment.
+        if (FloatUtils.fuzzyEquals(origin.x, mViewportRect.left))
+            mViewportBias.x = 0;
+        else
+            mViewportBias.x = ((mViewportRect.left - origin.x) > 0) ? MAX_BIAS : -MAX_BIAS;
+        if (FloatUtils.fuzzyEquals(origin.y, mViewportRect.top))
+            mViewportBias.y = 0;
+        else
+            mViewportBias.y = ((mViewportRect.top - origin.y) > 0) ? MAX_BIAS : -MAX_BIAS;
+
         mViewportRect.set(origin.x, origin.y,
                           origin.x + mViewportRect.width(),
                           origin.y + mViewportRect.height());
     }
 
     public void setSize(FloatSize size) {
         mViewportRect.right = mViewportRect.left + size.width;
         mViewportRect.bottom = mViewportRect.top + size.height;
@@ -213,16 +237,25 @@ public class ViewportMetrics {
 
         PointF origin = getOrigin();
         origin.offset(focus.x, focus.y);
         origin = PointUtils.scale(origin, scaleFactor);
         origin.offset(-focus.x, -focus.y);
         setOrigin(origin);
 
         mZoomFactor = newZoomFactor;
+
+        // Similar to setOrigin, set the viewport bias based on the focal point
+        // of the zoom so that a viewport based on these metrics will have a
+        // larger buffer based on the direction of movement when scaling.
+        //
+        // This is biased towards scaling outwards, as zooming in doesn't
+        // really require a viewport bias.
+        mViewportBias.set(((focus.x / mViewportRect.width()) * (2.0f * MAX_BIAS)) - MAX_BIAS,
+                          ((focus.y / mViewportRect.height()) * (2.0f * MAX_BIAS)) - MAX_BIAS);
     }
 
     /*
      * Returns the viewport metrics that represent a linear transition between `from` and `to` at
      * time `t`, which is on the scale [0, 1). This function interpolates the viewport rect, the
      * page size, the offset, and the zoom factor.
      */
     public ViewportMetrics interpolate(ViewportMetrics to, float t) {