Bug 1416316 - 2. Clean up NativePanZoomController; r=rbarker

Clean up the NativePanZoomController object including,

1) Remove references to LayerView because NPZC will be created and used
by LayerSession.

2) Rename `mDestroyed` to `mAttached` because NPZC now needs to support
cases where it's used before being attached, in addition to after being
destroyed.

3) Move origin of synthesized event coordinates from the screen to the
surface in native code, so we don't need to do the same thing in Java.

4) Invoke all callbacks from native code on the UI thread.

MozReview-Commit-ID: Fu4XIY59yKw

--HG--
extra : rebase_source : cb4d432cb940cfa92f3c0a931f1f2d2991932462
This commit is contained in:
Jim Chen 2017-11-30 13:25:50 -05:00
Родитель c8f7a24671
Коммит bd61ff7f2f
4 изменённых файлов: 166 добавлений и 125 удалений

Просмотреть файл

@ -406,7 +406,6 @@ gvjar.sources += [geckoview_source_dir + 'java/org/mozilla/gecko/' + x
'gfx/NativePanZoomController.java',
'gfx/OverscrollEdgeEffect.java',
'gfx/PanningPerfAPI.java',
'gfx/PanZoomController.java',
'gfx/PointUtils.java',
'gfx/RenderTask.java',
'gfx/StackScroller.java',

Просмотреть файл

@ -6,31 +6,25 @@
package org.mozilla.gecko.gfx;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.gfx.DynamicToolbarAnimator.PinReason;
import org.mozilla.gecko.mozglue.JNIObject;
import org.mozilla.gecko.util.ThreadUtils;
import org.json.JSONObject;
import android.graphics.PointF;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.SystemClock;
import android.util.Log;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.InputDevice;
import java.util.ArrayList;
class NativePanZoomController extends JNIObject implements PanZoomController {
public class NativePanZoomController extends JNIObject {
private static final String LOGTAG = "GeckoNPZC";
private final float MAX_SCROLL;
private final LayerView mView;
private boolean mDestroyed;
private float mPointerScrollFactor;
private final LayerSession mSession;
private final Rect mTempRect = new Rect();
private boolean mAttached;
private float mPointerScrollFactor = 64.0f;
private long mLastDownTime;
private SynthesizedEventState mPointerState;
@ -53,7 +47,7 @@ class NativePanZoomController extends JNIObject implements PanZoomController {
float x, float y, int buttons);
private boolean handleMotionEvent(MotionEvent event) {
if (mDestroyed) {
if (!mAttached) {
return false;
}
@ -97,7 +91,7 @@ class NativePanZoomController extends JNIObject implements PanZoomController {
}
private boolean handleScrollEvent(MotionEvent event) {
if (mDestroyed) {
if (!mAttached) {
return false;
}
@ -109,22 +103,23 @@ class NativePanZoomController extends JNIObject implements PanZoomController {
final MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
event.getPointerCoords(0, coords);
final float x = coords.x;
// Scroll events are not adjusted by the AndroidDyanmicToolbarAnimator so adjust the offset here.
final int toolbarHeight = (mView.mSession != null) ?
mView.mSession.getDynamicToolbarAnimator().getCurrentToolbarHeight() : 0;
final float y = coords.y - toolbarHeight;
// Translate surface origin to client origin for scroll events.
mSession.getSurfaceBounds(mTempRect);
final float x = coords.x - mTempRect.left;
final float y = coords.y - mTempRect.top;
final float hScroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL) *
mPointerScrollFactor;
final float vScroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL) *
mPointerScrollFactor;
return handleScrollEvent(event.getEventTime(), event.getMetaState(), x, y, hScroll, vScroll);
return handleScrollEvent(event.getEventTime(), event.getMetaState(), x, y,
hScroll, vScroll);
}
private boolean handleMouseEvent(MotionEvent event) {
if (mDestroyed) {
if (!mAttached) {
return false;
}
@ -136,52 +131,88 @@ class NativePanZoomController extends JNIObject implements PanZoomController {
final MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
event.getPointerCoords(0, coords);
final float x = coords.x;
// Mouse events are not adjusted by the AndroidDyanmicToolbarAnimator so adjust the offset
// here.
final int toolbarHeight = (mView.mSession != null) ?
mView.mSession.getDynamicToolbarAnimator().getCurrentToolbarHeight() : 0;
final float y = coords.y - toolbarHeight;
return handleMouseEvent(event.getActionMasked(), event.getEventTime(), event.getMetaState(), x, y, event.getButtonState());
// Translate surface origin to client origin for mouse events.
mSession.getSurfaceBounds(mTempRect);
final float x = coords.x - mTempRect.left;
final float y = coords.y - mTempRect.top;
return handleMouseEvent(event.getActionMasked(), event.getEventTime(),
event.getMetaState(), x, y, event.getButtonState());
}
NativePanZoomController(View view) {
MAX_SCROLL = 0.075f * view.getContext().getResources().getDisplayMetrics().densityDpi;
mView = (LayerView) view;
TypedValue outValue = new TypedValue();
if (view.getContext().getTheme().resolveAttribute(android.R.attr.listPreferredItemHeight, outValue, true)) {
mPointerScrollFactor = outValue.getDimension(view.getContext().getResources().getDisplayMetrics());
} else {
mPointerScrollFactor = MAX_SCROLL;
}
/* package */ NativePanZoomController(final LayerSession session) {
mSession = session;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// NOTE: This commented out block of code allows Fennec to generate
// mouse event instead of converting them to touch events.
// This gives Fennec similar behaviour to desktop when using
// a mouse.
//
// if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
// return handleMouseEvent(event);
// } else {
// return handleMotionEvent(event);
// }
/**
* Set the current scroll factor. The scroll factor is the maximum scroll amount that
* one scroll event may generate, in device pixels.
*
* @return Scroll factor.
*/
public void setScrollFactor(final float factor) {
ThreadUtils.assertOnUiThread();
mPointerScrollFactor = factor;
}
/**
* Get the current scroll factor.
*
* @return Scroll factor.
*/
public float getScrollFactor() {
ThreadUtils.assertOnUiThread();
return mPointerScrollFactor;
}
/**
* Process a touch event through the pan-zoom controller. Treat any mouse events as
* "touch" rather than as "mouse". Pointer coordinates should be relative to the
* display surface.
*
* @param event MotionEvent to process.
* @return True if the event was handled.
*/
public boolean onTouchEvent(final MotionEvent event) {
ThreadUtils.assertOnUiThread();
return handleMotionEvent(event);
}
@Override
/**
* Process a touch event through the pan-zoom controller. Treat any mouse events as
* "mouse" rather than as "touch". Pointer coordinates should be relative to the
* display surface.
*
* @param event MotionEvent to process.
* @return True if the event was handled.
*/
public boolean onMouseEvent(final MotionEvent event) {
ThreadUtils.assertOnUiThread();
if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
return handleMouseEvent(event);
}
return handleMotionEvent(event);
}
/**
* Process a non-touch motion event through the pan-zoom controller. Currently, hover
* and scroll events are supported. Pointer coordinates should be relative to the
* display surface.
*
* @param event MotionEvent to process.
* @return True if the event was handled.
*/
public boolean onMotionEvent(MotionEvent event) {
ThreadUtils.assertOnUiThread();
final int action = event.getActionMasked();
if (action == MotionEvent.ACTION_SCROLL) {
if (event.getDownTime() >= mLastDownTime) {
mLastDownTime = event.getDownTime();
} else if ((InputDevice.getDevice(event.getDeviceId()).getSources() & InputDevice.SOURCE_TOUCHPAD) == InputDevice.SOURCE_TOUCHPAD) {
} else if ((InputDevice.getDevice(event.getDeviceId()).getSources() &
InputDevice.SOURCE_TOUCHPAD) == InputDevice.SOURCE_TOUCHPAD) {
return false;
}
return handleScrollEvent(event);
@ -194,29 +225,35 @@ class NativePanZoomController extends JNIObject implements PanZoomController {
}
}
@Override @WrapForJNI(calledFrom = "ui") // PanZoomController
public void destroy() {
if (mDestroyed || !mView.isCompositorReady()) {
return;
@WrapForJNI(calledFrom = "ui")
private void setAttached(final boolean attached) {
if (attached) {
mAttached = true;
} else if (mAttached) {
mAttached = false;
disposeNative();
}
mDestroyed = true;
disposeNative();
}
@WrapForJNI(calledFrom = "ui", dispatchTo = "gecko_priority") @Override // JNIObject
@WrapForJNI(calledFrom = "ui", dispatchTo = "gecko") @Override // JNIObject
protected native void disposeNative();
@WrapForJNI(stubName = "SetIsLongpressEnabled") // Called from test thread.
private native void nativeSetIsLongpressEnabled(boolean isLongpressEnabled);
@Override // PanZoomController
/**
* Set whether Gecko should generate long-press events.
*
* @param isLongpressEnabled True if Gecko should generate long-press events.
*/
public void setIsLongpressEnabled(boolean isLongpressEnabled) {
if (!mDestroyed) {
ThreadUtils.assertOnUiThread();
if (mAttached) {
nativeSetIsLongpressEnabled(isLongpressEnabled);
}
}
private static class PointerInfo {
// We reserve one pointer ID for the mouse, so that tests don't have
// to worry about tracking pointer IDs if they just want to test mouse
@ -226,8 +263,8 @@ class NativePanZoomController extends JNIObject implements PanZoomController {
public int pointerId;
public int source;
public int screenX;
public int screenY;
public int surfaceX;
public int surfaceY;
public double pressure;
public int orientation;
@ -235,8 +272,8 @@ class NativePanZoomController extends JNIObject implements PanZoomController {
MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
coords.orientation = orientation;
coords.pressure = (float)pressure;
coords.x = screenX;
coords.y = screenY;
coords.x = surfaceX;
coords.y = surfaceY;
return coords;
}
}
@ -312,15 +349,9 @@ class NativePanZoomController extends JNIObject implements PanZoomController {
}
private void synthesizeNativePointer(int source, int pointerId, int eventType,
int screenX, int screenY, double pressure,
int clientX, int clientY, double pressure,
int orientation)
{
final View view = mView;
final int[] origin = new int[2];
view.getLocationOnScreen(origin);
screenX -= origin[0];
screenY -= origin[1];
if (mPointerState == null) {
mPointerState = new SynthesizedEventState();
}
@ -374,10 +405,15 @@ class NativePanZoomController extends JNIObject implements PanZoomController {
break;
}
// Translate client origin to surface origin.
mSession.getSurfaceBounds(mTempRect);
final int surfaceX = clientX + mTempRect.left;
final int surfaceY = clientY + mTempRect.top;
// Update the pointer with the new info
PointerInfo info = mPointerState.pointers.get(pointerIndex);
info.screenX = screenX;
info.screenY = screenY;
info.surfaceX = surfaceX;
info.surfaceY = surfaceY;
info.pressure = pressure;
info.orientation = orientation;
@ -409,12 +445,7 @@ class NativePanZoomController extends JNIObject implements PanZoomController {
/*edgeFlags*/ 0,
/*source*/ source,
/*flags*/ 0);
view.post(new Runnable() {
@Override
public void run() {
view.dispatchTouchEvent(event);
}
});
onTouchEvent(event);
// Forget about removed pointers
if (eventType == MotionEvent.ACTION_POINTER_UP ||
@ -426,21 +457,20 @@ class NativePanZoomController extends JNIObject implements PanZoomController {
}
}
@WrapForJNI(calledFrom = "gecko")
private void synthesizeNativeTouchPoint(int pointerId, int eventType, int screenX,
int screenY, double pressure, int orientation)
{
@WrapForJNI(calledFrom = "ui")
private void synthesizeNativeTouchPoint(int pointerId, int eventType, int clientX,
int clientY, double pressure, int orientation) {
if (pointerId == PointerInfo.RESERVED_MOUSE_POINTER_ID) {
throw new IllegalArgumentException("Pointer ID reserved for mouse");
}
synthesizeNativePointer(InputDevice.SOURCE_TOUCHSCREEN, pointerId,
eventType, screenX, screenY, pressure, orientation);
eventType, clientX, clientY, pressure, orientation);
}
@WrapForJNI(calledFrom = "gecko")
private void synthesizeNativeMouseEvent(int eventType, int screenX, int screenY) {
@WrapForJNI(calledFrom = "ui")
private void synthesizeNativeMouseEvent(int eventType, int clientX, int clientY) {
synthesizeNativePointer(InputDevice.SOURCE_MOUSE,
PointerInfo.RESERVED_MOUSE_POINTER_ID,
eventType, screenX, screenY, 0, 0);
eventType, clientX, clientY, 0, 0);
}
}

Просмотреть файл

@ -1,26 +0,0 @@
/* -*- 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 android.graphics.PointF;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
public interface PanZoomController {
static class Factory {
static PanZoomController create(View view) {
return new NativePanZoomController(view);
}
}
public void destroy();
public boolean onTouchEvent(MotionEvent event);
public boolean onMotionEvent(MotionEvent event);
public void setIsLongpressEnabled(boolean isLongpressEnabled);
}

Просмотреть файл

@ -432,7 +432,7 @@ public:
typedef NativePanZoomController::GlobalRef NPZCRef;
auto callDestroy = [] (const NPZCRef& npzc) {
npzc->Destroy();
npzc->SetAttached(false);
};
NativePanZoomController::GlobalRef npzc = mNPZC;
@ -905,11 +905,18 @@ public:
}
MOZ_ASSERT(aNPZC);
MOZ_ASSERT(!mWindow->mNPZCSupport);
auto npzc = NativePanZoomController::LocalRef(
jni::GetGeckoThreadEnv(),
NativePanZoomController::Ref::From(aNPZC));
mWindow->mNPZCSupport.Attach(npzc, mWindow, npzc);
DispatchToUiThread("LayerViewSupport::AttachNPZC",
[npzc = NativePanZoomController::GlobalRef(npzc)] {
npzc->SetAttached(true);
});
if (RefPtr<nsThread> uiThread = GetAndroidUiThread()) {
LayerSession::Compositor::GlobalRef compositor(mCompositor);
uiThread->Dispatch(NS_NewRunnableFunction(
@ -1358,6 +1365,7 @@ nsWindow::GeckoViewSupport::Transfer(const GeckoSession::Window::LocalRef& inst,
jni::Object::Param aSettings)
{
if (window.mNPZCSupport) {
MOZ_ASSERT(window.mLayerViewSupport);
window.mNPZCSupport.Detach();
}
@ -2245,8 +2253,20 @@ nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId,
MOZ_ASSERT(mNPZCSupport);
const auto& npzc = mNPZCSupport->GetJavaNPZC();
npzc->SynthesizeNativeTouchPoint(aPointerId, eventType, aPoint.x, aPoint.y,
aPointerPressure, aPointerOrientation);
const auto& bounds = FindTopLevel()->mBounds;
aPoint.x -= bounds.x;
aPoint.y -= bounds.y;
DispatchToUiThread(
"nsWindow::SynthesizeNativeTouchPoint",
[npzc = NativePanZoomController::GlobalRef(npzc),
aPointerId, eventType, aPoint,
aPointerPressure, aPointerOrientation] {
npzc->SynthesizeNativeTouchPoint(aPointerId, eventType,
aPoint.x, aPoint.y,
aPointerPressure,
aPointerOrientation);
});
return NS_OK;
}
@ -2260,7 +2280,17 @@ nsWindow::SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
MOZ_ASSERT(mNPZCSupport);
const auto& npzc = mNPZCSupport->GetJavaNPZC();
npzc->SynthesizeNativeMouseEvent(aNativeMessage, aPoint.x, aPoint.y);
const auto& bounds = FindTopLevel()->mBounds;
aPoint.x -= bounds.x;
aPoint.y -= bounds.y;
DispatchToUiThread(
"nsWindow::SynthesizeNativeMouseEvent",
[npzc = NativePanZoomController::GlobalRef(npzc),
aNativeMessage, aPoint] {
npzc->SynthesizeNativeMouseEvent(aNativeMessage,
aPoint.x, aPoint.y);
});
return NS_OK;
}
@ -2272,8 +2302,16 @@ nsWindow::SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
MOZ_ASSERT(mNPZCSupport);
const auto& npzc = mNPZCSupport->GetJavaNPZC();
npzc->SynthesizeNativeMouseEvent(sdk::MotionEvent::ACTION_HOVER_MOVE,
aPoint.x, aPoint.y);
const auto& bounds = FindTopLevel()->mBounds;
aPoint.x -= bounds.x;
aPoint.y -= bounds.y;
DispatchToUiThread(
"nsWindow::SynthesizeNativeMouseMove",
[npzc = NativePanZoomController::GlobalRef(npzc), aPoint] {
npzc->SynthesizeNativeMouseEvent(sdk::MotionEvent::ACTION_HOVER_MOVE,
aPoint.x, aPoint.y);
});
return NS_OK;
}