diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index 44ad3a3d03f4..91528cf873d9 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -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', diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/NativePanZoomController.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/NativePanZoomController.java index 0fd527b2a41e..9108c1355538 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/NativePanZoomController.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/NativePanZoomController.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); } } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/PanZoomController.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/PanZoomController.java deleted file mode 100644 index 22ce16f8b7d5..000000000000 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/PanZoomController.java +++ /dev/null @@ -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); -} diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 741f690edd3d..4a51c045c65f 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -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 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; }