Bug 744241 - Make the displayport strategy options preffable. r=Cwiiis
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 13 Apr 2012 10:28:10 -0400
changeset 91611 17e8b7678990045f4eea5e80fdfbb8b0c54c2060
parent 91610 c0975fb1e62dc57e436f2f6aa3781433feeabe52
child 91612 84351dbcd62d12769fb601e11cc098849faee073
push id22465
push usermak77@bonardo.net
push dateSat, 14 Apr 2012 11:58:29 +0000
treeherdermozilla-central@6880c195054f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersCwiiis
bugs744241
milestone14.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 744241 - Make the displayport strategy options preffable. r=Cwiiis
mobile/android/app/mobile.js
mobile/android/base/gfx/DisplayPortCalculator.java
mobile/android/base/gfx/GeckoLayerClient.java
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -357,19 +357,30 @@ pref("places.frecency.downloadVisitBonus
 pref("places.frecency.permRedirectVisitBonus", 0);
 pref("places.frecency.tempRedirectVisitBonus", 0);
 pref("places.frecency.defaultVisitBonus", 0);
 pref("places.frecency.unvisitedBookmarkBonus", 140);
 pref("places.frecency.unvisitedTypedBonus", 200);
 
 // disable color management
 pref("gfx.color_management.mode", 0);
+
 #ifdef ANDROID
 // 0=fixed margin, 1=velocity bias, 2=dynamic resolution, 3=no margins
 pref("gfx.displayport.strategy", 1);
+// all of the following displayport strategy prefs will be divided by 1000
+// to obtain some multiplier which is then used in the strategy.
+// fixed margin strategy options
+pref("gfx.displayport.strategy_fm.multiplier", -1); // displayport dimension multiplier
+pref("gfx.displayport.strategy_fm.danger_x", -1); // danger zone on x-axis when multiplied by viewport width
+pref("gfx.displayport.strategy_fm.danger_y", -1); // danger zone on y-axis when multiplied by viewport height
+// velocity bias strategy options
+pref("gfx.displayport.strategy_vb.multiplier", -1); // displayport dimension multiplier
+pref("gfx.displayport.strategy_vb.threshold", -1); // velocity threshold in pixels/frame when multiplied by screen DPI
+pref("gfx.displayport.strategy_vb.reverse_buffer", -1); // fraction of buffer to keep in reverse direction from scroll
 #endif
 
 // don't allow JS to move and resize existing windows
 pref("dom.disable_window_move_resize", true);
 
 // prevent click image resizing for nsImageDocument
 pref("browser.enable_click_image_resizing", false);
 
--- a/mobile/android/base/gfx/DisplayPortCalculator.java
+++ b/mobile/android/base/gfx/DisplayPortCalculator.java
@@ -1,60 +1,93 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
+import java.util.Map;
 import android.graphics.PointF;
 import android.graphics.RectF;
 import android.util.Log;
+import org.json.JSONArray;
 import org.mozilla.gecko.FloatUtils;
 import org.mozilla.gecko.GeckoAppShell;
 
 final class DisplayPortCalculator {
     private static final String LOGTAG = "GeckoDisplayPortCalculator";
     private static final PointF ZERO_VELOCITY = new PointF(0, 0);
 
-    private static DisplayPortStrategy sStrategy = new VelocityBiasStrategy();
+    private static final String PREF_DISPLAYPORT_STRATEGY = "gfx.displayport.strategy";
+    private static final String PREF_DISPLAYPORT_FM_MULTIPLIER = "gfx.displayport.strategy_fm.multiplier";
+    private static final String PREF_DISPLAYPORT_FM_DANGER_X = "gfx.displayport.strategy_fm.danger_x";
+    private static final String PREF_DISPLAYPORT_FM_DANGER_Y = "gfx.displayport.strategy_fm.danger_y";
+    private static final String PREF_DISPLAYPORT_VB_MULTIPLIER = "gfx.displayport.strategy_vb.multiplier";
+    private static final String PREF_DISPLAYPORT_VB_VELOCITY_THRESHOLD = "gfx.displayport.strategy_vb.threshold";
+    private static final String PREF_DISPLAYPORT_VB_REVERSE_BUFFER = "gfx.displayport.strategy_vb.reverse_buffer";
+
+    private static DisplayPortStrategy sStrategy = new VelocityBiasStrategy(null);
 
     static DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity) {
         return sStrategy.calculate(metrics, (velocity == null ? ZERO_VELOCITY : velocity));
     }
 
     static boolean aboutToCheckerboard(ImmutableViewportMetrics metrics, PointF velocity, DisplayPortMetrics displayPort) {
         if (displayPort == null) {
             return true;
         }
         return sStrategy.aboutToCheckerboard(metrics, (velocity == null ? ZERO_VELOCITY : velocity), displayPort);
     }
 
+    static void addPrefNames(JSONArray prefs) {
+        prefs.put(PREF_DISPLAYPORT_STRATEGY);
+        prefs.put(PREF_DISPLAYPORT_FM_MULTIPLIER);
+        prefs.put(PREF_DISPLAYPORT_FM_DANGER_X);
+        prefs.put(PREF_DISPLAYPORT_FM_DANGER_Y);
+        prefs.put(PREF_DISPLAYPORT_VB_MULTIPLIER);
+        prefs.put(PREF_DISPLAYPORT_VB_VELOCITY_THRESHOLD);
+        prefs.put(PREF_DISPLAYPORT_VB_REVERSE_BUFFER);
+    }
+
     /**
      * Set the active strategy to use.
      * See the gfx.displayport.strategy pref in mobile/android/app/mobile.js to see the
      * mapping between ints and strategies.
      */
-    static void setStrategy(int strategy) {
+    static boolean setStrategy(Map<String, Integer> prefs) {
+        Integer strategy = prefs.get(PREF_DISPLAYPORT_STRATEGY);
+        if (strategy == null) {
+            return false;
+        }
+
         switch (strategy) {
             case 0:
-            default:
-                sStrategy = new FixedMarginStrategy();
+                sStrategy = new FixedMarginStrategy(prefs);
                 break;
             case 1:
-                sStrategy = new VelocityBiasStrategy();
+                sStrategy = new VelocityBiasStrategy(prefs);
                 break;
             case 2:
-                sStrategy = new DynamicResolutionStrategy();
+                sStrategy = new DynamicResolutionStrategy(prefs);
                 break;
             case 3:
-                sStrategy = new NoMarginStrategy();
+                sStrategy = new NoMarginStrategy(prefs);
                 break;
+            default:
+                Log.e(LOGTAG, "Invalid strategy index specified");
+                return false;
         }
-        Log.i(LOGTAG, "Set strategy " + sStrategy.getClass().getName());
+        Log.i(LOGTAG, "Set strategy " + sStrategy.toString());
+        return true;
+    }
+
+    private static float getFloatPref(Map<String, Integer> prefs, String prefName, int defaultValue) {
+        Integer value = (prefs == null ? null : prefs.get(prefName));
+        return (float)(value == null || value < 0 ? defaultValue : value) / 1000f;
     }
 
     private interface DisplayPortStrategy {
         /** Calculates a displayport given a viewport and panning velocity. */
         public DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity);
         /** Returns true if a checkerboard is about to be visible and we should not throttle drawing. */
         public boolean aboutToCheckerboard(ImmutableViewportMetrics metrics, PointF velocity, DisplayPortMetrics displayPort);
     }
@@ -130,46 +163,61 @@ final class DisplayPortCalculator {
         }
         return margins;
     }
 
     /**
      * This class implements the variation where we basically don't bother with a a display port.
      */
     private static class NoMarginStrategy implements DisplayPortStrategy {
+        NoMarginStrategy(Map<String, Integer> prefs) {
+            // no prefs in this strategy
+        }
+
         public DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity) {
             return new DisplayPortMetrics(metrics.viewportRectLeft,
                     metrics.viewportRectTop,
                     metrics.viewportRectRight,
                     metrics.viewportRectBottom,
                     metrics.zoomFactor);
         }
 
         public boolean aboutToCheckerboard(ImmutableViewportMetrics metrics, PointF velocity, DisplayPortMetrics displayPort) {
             return true;
         }
+
+        @Override
+        public String toString() {
+            return "NoMarginStrategy";
+        }
     }
 
     /**
      * This class implements the variation where we use a fixed-size margin on the display port.
      * The margin is always 300 pixels in all directions, except when we are (a) approaching a page
      * boundary, and/or (b) if we are limited by the page size. In these cases we try to maintain
      * the area of the display port by (a) shifting the buffer to the other side on the same axis,
      * and/or (b) increasing the buffer on the other axis to compensate for the reduced buffer on
      * one axis.
      */
     private static class FixedMarginStrategy implements DisplayPortStrategy {
         // The length of each axis of the display port will be the corresponding view length
         // multiplied by this factor.
-        private static final float SIZE_MULTIPLIER = 1.5f;
+        private final float SIZE_MULTIPLIER;
 
         // If the visible rect is within the danger zone (measured as a fraction of the view size
         // from the edge of the displayport) we start redrawing to minimize checkerboarding.
-        private static final float DANGER_ZONE_X_MULTIPLIER = 0.10f;
-        private static final float DANGER_ZONE_Y_MULTIPLIER = 0.20f;
+        private final float DANGER_ZONE_X_MULTIPLIER;
+        private final float DANGER_ZONE_Y_MULTIPLIER;
+
+        FixedMarginStrategy(Map<String, Integer> prefs) {
+            SIZE_MULTIPLIER = getFloatPref(prefs, PREF_DISPLAYPORT_FM_MULTIPLIER, 1500);
+            DANGER_ZONE_X_MULTIPLIER = getFloatPref(prefs, PREF_DISPLAYPORT_FM_DANGER_X, 100);
+            DANGER_ZONE_Y_MULTIPLIER = getFloatPref(prefs, PREF_DISPLAYPORT_FM_DANGER_Y, 200);
+        }
 
         public DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity) {
             float displayPortWidth = metrics.getWidth() * SIZE_MULTIPLIER;
             float displayPortHeight = metrics.getHeight() * SIZE_MULTIPLIER;
 
             // we need to avoid having a display port that is larger than the page, or we will end up
             // painting things outside the page bounds (bug 729169). we simultaneously need to make
             // the display port as large as possible so that we redraw less. reshape the display
@@ -203,35 +251,46 @@ final class DisplayPortCalculator {
 
         public boolean aboutToCheckerboard(ImmutableViewportMetrics metrics, PointF velocity, DisplayPortMetrics displayPort) {
             // Increase the size of the viewport based on the danger zone multiplier (and clamp to page
             // boundaries), and intersect it with the current displayport to determine whether we're
             // close to checkerboarding.
             RectF adjustedViewport = expandByDangerZone(metrics.getViewport(), DANGER_ZONE_X_MULTIPLIER, DANGER_ZONE_Y_MULTIPLIER, metrics);
             return !displayPort.contains(adjustedViewport);
         }
+
+        @Override
+        public String toString() {
+            return "FixedMarginStrategy mult=" + SIZE_MULTIPLIER + ", dangerX=" + DANGER_ZONE_X_MULTIPLIER + ", dangerY=" + DANGER_ZONE_Y_MULTIPLIER;
+        }
     }
 
     /**
      * This class implements the variation with a small fixed-size margin with velocity bias.
      * In this variation, the default margins are pretty small relative to the view size, but
      * they are affected by the panning velocity. Specifically, if we are panning on one axis,
      * we remove the margins on the other axis because we are likely axis-locked. Also once
      * we are panning in one direction above a certain threshold velocity, we shift the buffer
      * so that it is almost entirely in the direction of the pan, with a little bit in the
      * reverse direction.
      */
     private static class VelocityBiasStrategy implements DisplayPortStrategy {
         // The length of each axis of the display port will be the corresponding view length
         // multiplied by this factor.
-        private static final float SIZE_MULTIPLIER = 1.5f;
+        private final float SIZE_MULTIPLIER;
         // The velocity above which we apply the velocity bias
-        private static final float VELOCITY_THRESHOLD = GeckoAppShell.getDpi() / 32f;
+        private final float VELOCITY_THRESHOLD;
         // How much of the buffer to keep in the reverse direction of the velocity
-        private static final float REVERSE_BUFFER = 0.2f;
+        private final float REVERSE_BUFFER;
+
+        VelocityBiasStrategy(Map<String, Integer> prefs) {
+            SIZE_MULTIPLIER = getFloatPref(prefs, PREF_DISPLAYPORT_VB_MULTIPLIER, 1500);
+            VELOCITY_THRESHOLD = GeckoAppShell.getDpi() * getFloatPref(prefs, PREF_DISPLAYPORT_VB_VELOCITY_THRESHOLD, 32);
+            REVERSE_BUFFER = getFloatPref(prefs, PREF_DISPLAYPORT_VB_REVERSE_BUFFER, 200);
+        }
 
         public DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity) {
             float displayPortWidth = metrics.getWidth() * SIZE_MULTIPLIER;
             float displayPortHeight = metrics.getHeight() * SIZE_MULTIPLIER;
 
             // but if we're panning on one axis, set the margins for the other axis to zero since we are likely
             // axis locked and won't be displaying that extra area.
             if (Math.abs(velocity.x) > VELOCITY_THRESHOLD && FloatUtils.fuzzyEquals(velocity.y, 0)) {
@@ -282,16 +341,21 @@ final class DisplayPortCalculator {
         public boolean aboutToCheckerboard(ImmutableViewportMetrics metrics, PointF velocity, DisplayPortMetrics displayPort) {
             // Since we have such a small margin, we want to be drawing more aggressively. At the start of a
             // pan the velocity is going to be large so we're almost certainly going to go into checkerboard
             // on every frame, so drawing all the time seems like the right thing. At the end of the pan we
             // want to re-center the displayport and draw stuff on all sides, so again we don't want to throttle
             // there. When we're not panning we're not drawing anyway so it doesn't make a difference there.
             return true;
         }
+
+        @Override
+        public String toString() {
+            return "VelocityBiasStrategy mult=" + SIZE_MULTIPLIER + ", threshold=" + VELOCITY_THRESHOLD + ", reverse=" + REVERSE_BUFFER;
+        }
     }
 
     /**
      * This class implements the variation where we draw more of the page at low resolution while panning.
      * In this variation, as we pan faster, we increase the page area we are drawing, but reduce the draw
      * resolution to compensate. This results in the same device-pixel area drawn; the compositor then
      * scales this up to the viewport zoom level. This results in a large area of the page drawn but it
      * looks blurry. The assumption is that drawing extra that we never display is better than checkerboarding,
@@ -344,16 +408,20 @@ final class DisplayPortCalculator {
         // viewport size that we use as an extra "danger zone" around the viewport; if this danger
         // zone falls outside the display port then we are approaching the point at which we will
         // checkerboard, and hence should start drawing. Note that if DANGER_ZONE_MULTIPLIER is
         // greater than (SIZE_MULTIPLIER - 1.0f), then at zero velocity we will always be in the
         // danger zone, and thus will be constantly drawing.
         private static final float PREDICTION_VELOCITY_MULTIPLIER = 30.0f;
         private static final float DANGER_ZONE_MULTIPLIER = 0.20f; // must be less than (SIZE_MULTIPLIER - 1.0f)
 
+        DynamicResolutionStrategy(Map<String, Integer> prefs) {
+            // ignore prefs for now
+        }
+
         public DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity) {
             float displayPortWidth = metrics.getWidth() * SIZE_MULTIPLIER;
             float displayPortHeight = metrics.getHeight() * SIZE_MULTIPLIER;
 
             // for resolution calculation purposes, we need to know what the adjusted display port dimensions
             // would be if we had zero velocity, so calculate that here before we increase the display port
             // based on velocity.
             FloatSize reshapedSize = reshapeForPage(displayPortWidth, displayPortHeight, metrics);
@@ -471,10 +539,15 @@ final class DisplayPortCalculator {
                 }
             }
 
             // then we expand the viewport evenly in all directions just to have an extra
             // safety zone. this also clamps it to page bounds.
             predictedViewport = expandByDangerZone(predictedViewport, DANGER_ZONE_MULTIPLIER, DANGER_ZONE_MULTIPLIER, metrics);
             return !displayPort.contains(predictedViewport);
         }
+
+        @Override
+        public String toString() {
+            return "DynamicResolutionStrategy";
+        }
     }
 }
--- a/mobile/android/base/gfx/GeckoLayerClient.java
+++ b/mobile/android/base/gfx/GeckoLayerClient.java
@@ -51,21 +51,22 @@ import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.SystemClock;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.View;
+import java.util.Map;
+import java.util.HashMap;
 
 public class GeckoLayerClient implements GeckoEventResponder,
                                          LayerView.Listener {
     private static final String LOGTAG = "GeckoLayerClient";
-    private static final String PREF_DISPLAYPORT_STRATEGY = "gfx.displayport.strategy";
 
     private LayerController mLayerController;
     private LayerRenderer mLayerRenderer;
     private boolean mLayerRendererInitialized;
 
     private IntSize mScreenSize;
     private IntSize mWindowSize;
     private DisplayPortMetrics mDisplayPort;
@@ -114,17 +115,20 @@ public class GeckoLayerClient implements
         GeckoAppShell.registerGeckoEventListener("Checkerboard:Toggle", this);
         GeckoAppShell.registerGeckoEventListener("Preferences:Data", this);
 
         view.setListener(this);
         view.setLayerRenderer(mLayerRenderer);
         layerController.setRoot(mRootLayer);
 
         sendResizeEventIfNecessary(true);
-        GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Preferences:Get", "[ \"" + PREF_DISPLAYPORT_STRATEGY + "\" ]"));
+
+        JSONArray prefs = new JSONArray();
+        DisplayPortCalculator.addPrefNames(prefs);
+        GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Preferences:Get", prefs.toString()));
     }
 
     DisplayPortMetrics getDisplayPort() {
         return mDisplayPort;
     }
 
     /* Informs Gecko that the screen size has changed. */
     private void sendResizeEventIfNecessary(boolean force) {
@@ -247,22 +251,23 @@ public class GeckoLayerClient implements
                 ImmutableViewportMetrics newMetrics = new ImmutableViewportMetrics(new ViewportMetrics(message));
                 mReturnDisplayPort = DisplayPortCalculator.calculate(newMetrics, null);
             } else if ("Checkerboard:Toggle".equals(event)) {
                 boolean showChecks = message.getBoolean("value");
                 mLayerController.setCheckerboardShowChecks(showChecks);
                 Log.i(LOGTAG, "Showing checks: " + showChecks);
             } else if ("Preferences:Data".equals(event)) {
                 JSONArray jsonPrefs = message.getJSONArray("preferences");
+                Map<String, Integer> prefValues = new HashMap<String, Integer>();
                 for (int i = jsonPrefs.length() - 1; i >= 0; i--) {
                     JSONObject pref = jsonPrefs.getJSONObject(i);
-                    if (pref.getString("name").equals(PREF_DISPLAYPORT_STRATEGY)) {
-                        DisplayPortCalculator.setStrategy(pref.getInt("value"));
-                        GeckoAppShell.unregisterGeckoEventListener("Preferences:Data", this);
-                    }
+                    prefValues.put(pref.getString("name"), pref.getInt("value"));
+                }
+                if (DisplayPortCalculator.setStrategy(prefValues)) {
+                    GeckoAppShell.unregisterGeckoEventListener("Preferences:Data", this);
                 }
             }
         } catch (JSONException e) {
             Log.e(LOGTAG, "Error decoding JSON in " + event + " handler", e);
         }
     }
 
     /** Implementation of GeckoEventResponder. */