| Index: content/public/android/java/src/org/chromium/content/browser/input/JoystickScrollProvider.java | 
| diff --git a/content/public/android/java/src/org/chromium/content/browser/input/JoystickScrollProvider.java b/content/public/android/java/src/org/chromium/content/browser/input/JoystickScrollProvider.java | 
| index 1336b78b3982b6630d0ad30e90bbc4cf88c6ee73..0e67e74cfe23bb07ea4a2cf210b3bee067710695 100644 | 
| --- a/content/public/android/java/src/org/chromium/content/browser/input/JoystickScrollProvider.java | 
| +++ b/content/public/android/java/src/org/chromium/content/browser/input/JoystickScrollProvider.java | 
| @@ -4,17 +4,24 @@ | 
|  | 
| package org.chromium.content.browser.input; | 
|  | 
| +import android.content.Context; | 
| import android.util.TypedValue; | 
| import android.view.InputDevice; | 
| import android.view.MotionEvent; | 
| +import android.view.View; | 
| import android.view.animation.AnimationUtils; | 
|  | 
| import org.chromium.base.Log; | 
| -import org.chromium.content.browser.ContentViewCore; | 
| +import org.chromium.base.annotations.CalledByNative; | 
| +import org.chromium.base.annotations.JNINamespace; | 
| +import org.chromium.content_public.browser.WebContents; | 
| + | 
| +import java.lang.ref.WeakReference; | 
|  | 
| /** | 
| * This class implements auto scrolling and panning for gamepad left joystick motion event. | 
| */ | 
| +@JNINamespace("content") | 
| public class JoystickScrollProvider { | 
| private static final String TAG = "JoystickScroll"; | 
|  | 
| @@ -24,11 +31,13 @@ public class JoystickScrollProvider { | 
| private static final float JOYSTICK_SCROLL_DEADZONE = 0.2f; | 
| private static final float SCROLL_FACTOR_FALLBACK = 128f; | 
|  | 
| -    private final ContentViewCore mView; | 
| +    private View mContainerView; | 
| +    private long mNativeJoystickScrollProvider; | 
|  | 
| private float mScrollVelocityX; | 
| private float mScrollVelocityY; | 
| private float mScrollFactor; | 
| +    private float mDipScale = 1.0f; | 
|  | 
| private long mLastAnimateTimeMillis; | 
|  | 
| @@ -38,14 +47,19 @@ public class JoystickScrollProvider { | 
|  | 
| /** | 
| * Constructs a new JoystickScrollProvider. | 
| -     * | 
| -     * @param contentview The ContentViewCore used to create this. | 
| */ | 
| -    public JoystickScrollProvider(ContentViewCore contentView) { | 
| -        mView = contentView; | 
| +    public JoystickScrollProvider(WebContents webContents, View containerView) { | 
| +        mNativeJoystickScrollProvider = nativeInit(webContents); | 
| +        mContainerView = containerView; | 
| mEnabled = true; | 
| } | 
|  | 
| +    @CalledByNative | 
| +    private void onNativeObjectDestroyed(long nativePointer) { | 
| +        assert nativePointer == mNativeJoystickScrollProvider; | 
| +        mNativeJoystickScrollProvider = 0; | 
| +    } | 
| + | 
| /** | 
| * This function enables or disables scrolling through joystick. | 
| * @param enabled Decides whether joystick scrolling should be | 
| @@ -56,6 +70,21 @@ public class JoystickScrollProvider { | 
| if (!enabled) stop(); | 
| } | 
|  | 
| +    public void setDeviceScaleFactor(float dipScale, WeakReference<Context> displayContext) { | 
| +        mDipScale = dipScale; | 
| + | 
| +        Context context = displayContext.get(); | 
| +        TypedValue outValue = new TypedValue(); | 
| +        if (context != null && context.getTheme().resolveAttribute( | 
| +                android.R.attr.listPreferredItemHeight, outValue, true)) { | 
| +            mScrollFactor = outValue.getDimension(context.getResources().getDisplayMetrics()); | 
| +        } else { | 
| +            Log.d(TAG, "Theme attribute listPreferredItemHeight not defined" | 
| +                            + " switching to fallback scroll factor "); | 
| +            mScrollFactor = SCROLL_FACTOR_FALLBACK * mDipScale; | 
| +        } | 
| +    } | 
| + | 
| /** | 
| * This function processes motion event and computes new | 
| * scroll offest in pixels which is propertional to left joystick | 
| @@ -72,7 +101,13 @@ public class JoystickScrollProvider { | 
| Log.d(TAG, "Joystick left stick axis: " + event.getAxisValue(MotionEvent.AXIS_X) + "," | 
| + event.getAxisValue(MotionEvent.AXIS_Y)); | 
|  | 
| -        computeNewScrollVelocity(event); | 
| +        assert mScrollFactor != 0; | 
| + | 
| +        mScrollVelocityX = getFilteredAxisValue(event, MotionEvent.AXIS_X) * mScrollFactor | 
| +                * JOYSTICK_SCROLL_FACTOR_MULTIPLIER; | 
| +        mScrollVelocityY = getFilteredAxisValue(event, MotionEvent.AXIS_Y) * mScrollFactor | 
| +                * JOYSTICK_SCROLL_FACTOR_MULTIPLIER; | 
| + | 
| if (mScrollVelocityX == 0 && mScrollVelocityY == 0) { | 
| stop(); | 
| return false; | 
| @@ -86,7 +121,7 @@ public class JoystickScrollProvider { | 
| }; | 
| } | 
| if (mLastAnimateTimeMillis == 0) { | 
| -            mView.getContainerView().postOnAnimation(mScrollRunnable); | 
| +            mContainerView.postOnAnimation(mScrollRunnable); | 
| mLastAnimateTimeMillis = AnimationUtils.currentAnimationTimeMillis(); | 
| } | 
| return true; | 
| @@ -100,9 +135,14 @@ public class JoystickScrollProvider { | 
| final long dt = timeMillis - mLastAnimateTimeMillis; | 
| final float dx = (mScrollVelocityX * dt / 1000.f); | 
| final float dy = (mScrollVelocityY * dt / 1000.f); | 
| -        mView.scrollBy(dx, dy, true); | 
| + | 
| +        if (mNativeJoystickScrollProvider != 0) { | 
| +            nativeScrollBy( | 
| +                    mNativeJoystickScrollProvider, timeMillis, dx / mDipScale, dy / mDipScale); | 
| +        } | 
| + | 
| mLastAnimateTimeMillis = timeMillis; | 
| -        mView.getContainerView().postOnAnimation(mScrollRunnable); | 
| +        mContainerView.postOnAnimation(mScrollRunnable); | 
| } | 
|  | 
| private void stop() { | 
| @@ -110,29 +150,6 @@ public class JoystickScrollProvider { | 
| } | 
|  | 
| /** | 
| -     * Translates joystick axes movement to a scroll velocity. | 
| -     */ | 
| -    private void computeNewScrollVelocity(MotionEvent event) { | 
| -        if (mScrollFactor == 0) { | 
| -            TypedValue outValue = new TypedValue(); | 
| -            if (!mView.getContext().getTheme().resolveAttribute( | 
| -                        android.R.attr.listPreferredItemHeight, outValue, true)) { | 
| -                mScrollFactor = outValue.getDimension( | 
| -                        mView.getContext().getResources().getDisplayMetrics()); | 
| -            } else { | 
| -                Log.d(TAG, "Theme attribute listPreferredItemHeight not defined" | 
| -                                + "switching to fallback scroll factor "); | 
| -                mScrollFactor = SCROLL_FACTOR_FALLBACK | 
| -                        * mView.getRenderCoordinates().getDeviceScaleFactor(); | 
| -            } | 
| -        } | 
| -        mScrollVelocityX = getFilteredAxisValue(event, MotionEvent.AXIS_X) * mScrollFactor | 
| -                * JOYSTICK_SCROLL_FACTOR_MULTIPLIER; | 
| -        mScrollVelocityY = getFilteredAxisValue(event, MotionEvent.AXIS_Y) * mScrollFactor | 
| -                * JOYSTICK_SCROLL_FACTOR_MULTIPLIER; | 
| -    } | 
| - | 
| -    /** | 
| * Removes noise from joystick motion events. | 
| */ | 
| private float getFilteredAxisValue(MotionEvent event, int axis) { | 
| @@ -143,4 +160,8 @@ public class JoystickScrollProvider { | 
| } | 
| return 0f; | 
| } | 
| + | 
| +    private native long nativeInit(WebContents webContents); | 
| +    private native void nativeScrollBy( | 
| +            long nativeJoystickScrollProvider, long timeMs, float dxDip, float dyDip); | 
| } | 
|  |