Bug 1416316 - 1. Move overscroll to LayerSession; r?rbarker
There is some overscroll handling code in NativePanZoomController that
should be moved, along with other overscroll code in LayerView, to
LayerSession. LayerSession now provides a getter for
OverscrollEdgeEffect, which is cleaned up to have a public API with
documentation.
MozReview-Commit-ID: LkKHFS8OkR7
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -399,17 +399,16 @@ gvjar.sources += [geckoview_source_dir +
'gfx/FullScreenState.java',
'gfx/GeckoDisplay.java',
'gfx/GeckoSurface.java',
'gfx/GeckoSurfaceTexture.java',
'gfx/IntSize.java',
'gfx/LayerSession.java',
'gfx/LayerView.java',
'gfx/NativePanZoomController.java',
- 'gfx/Overscroll.java',
'gfx/OverscrollEdgeEffect.java',
'gfx/PanningPerfAPI.java',
'gfx/PanZoomController.java',
'gfx/PointUtils.java',
'gfx/RenderTask.java',
'gfx/StackScroller.java',
'gfx/SurfaceAllocator.java',
'gfx/SurfaceAllocatorService.java',
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
@@ -6,19 +6,21 @@
package org.mozilla.gecko;
import org.mozilla.gecko.gfx.DynamicToolbarAnimator;
import org.mozilla.gecko.gfx.GeckoDisplay;
import org.mozilla.gecko.gfx.LayerView;
import android.content.Context;
+import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.Build;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
@@ -185,16 +187,29 @@ public class GeckoView extends LayerView
if (mSession != null) {
mSession.removeDisplay(mDisplay);
}
if (session != null) {
session.addDisplay(mDisplay);
}
+ final Context context = getContext();
+ session.getOverscrollEdgeEffect().setTheme(context);
+ session.getOverscrollEdgeEffect().setInvalidationCallback(new Runnable() {
+ @Override
+ public void run() {
+ if (Build.VERSION.SDK_INT >= 16) {
+ GeckoView.this.postInvalidateOnAnimation();
+ } else {
+ GeckoView.this.postInvalidateDelayed(10);
+ }
+ }
+ });
+
mSession = session;
}
public GeckoSession getSession() {
return mSession;
}
public EventDispatcher getEventDispatcher() {
@@ -382,9 +397,18 @@ public class GeckoView extends LayerView
mInputConnectionListener.onKeyMultiple(keyCode, repeatCount, event);
}
@Override
public boolean isIMEEnabled() {
return mInputConnectionListener != null &&
mInputConnectionListener.isIMEEnabled();
}
+
+ @Override
+ public void dispatchDraw(final Canvas canvas) {
+ super.dispatchDraw(canvas);
+
+ if (mSession != null) {
+ mSession.getOverscrollEdgeEffect().draw(canvas);
+ }
+ }
}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/LayerSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/LayerSession.java
@@ -139,22 +139,40 @@ public class LayerSession {
// The compositor invokes this function just before compositing a frame where the
// document is different from the document composited on the last frame. In these
// cases, the viewport information we have in Java is no longer valid and needs to
// be replaced with the new viewport information provided.
@WrapForJNI(calledFrom = "ui")
private void updateRootFrameMetrics(float scrollX, float scrollY, float zoom) {
LayerSession.this.onMetricsChanged(scrollX, scrollY, zoom);
}
+
+ @WrapForJNI(calledFrom = "ui")
+ private void updateOverscrollVelocity(final float x, final float y) {
+ LayerSession.this.updateOverscrollVelocity(x, y);
+ }
+
+ @WrapForJNI(calledFrom = "ui")
+ private void updateOverscrollOffset(final float x, final float y) {
+ LayerSession.this.updateOverscrollOffset(x, y);
+ }
+
+ @WrapForJNI(calledFrom = "ui")
+ private void onSelectionCaretDrag(final boolean dragging) {
+ // Active SelectionCaretDrag requires DynamicToolbarAnimator to be pinned to
+ // avoid unwanted scroll interactions.
+ LayerSession.this.onSelectionCaretDrag(dragging);
+ }
}
protected final Compositor mCompositor = new Compositor();
// All fields are accessed on UI thread only.
private GeckoDisplay mDisplay;
+ private OverscrollEdgeEffect mOverscroll;
private DynamicToolbarAnimator mToolbar;
private boolean mAttachedCompositor;
private boolean mCalledCreateCompositor;
private boolean mCompositorReady;
private Surface mSurface;
// All fields of coordinates are in screen units.
@@ -171,16 +189,30 @@ public class LayerSession {
/* package */ GeckoDisplay getDisplay() {
if (DEBUG) {
ThreadUtils.assertOnUiThread();
}
return mDisplay;
}
/**
+ * Get the OverscrollEdgeEffect instance for this session.
+ *
+ * @return OverscrollEdgeEffect instance.
+ */
+ public OverscrollEdgeEffect getOverscrollEdgeEffect() {
+ ThreadUtils.assertOnUiThread();
+
+ if (mOverscroll == null) {
+ mOverscroll = new OverscrollEdgeEffect(this);
+ }
+ return mOverscroll;
+ }
+
+ /**
* Get the DynamicToolbarAnimator instance for this session.
*
* @return DynamicToolbarAnimator instance.
*/
public @NonNull DynamicToolbarAnimator getDynamicToolbarAnimator() {
ThreadUtils.assertOnUiThread();
if (mToolbar == null) {
@@ -383,16 +415,53 @@ public class LayerSession {
mSurface = null;
}
if (mToolbar != null) {
mToolbar.onCompositorReady();
}
}
+ /* package */ void updateOverscrollVelocity(final float x, final float y) {
+ if (DEBUG) {
+ ThreadUtils.assertOnUiThread();
+ }
+
+ if (mOverscroll == null) {
+ return;
+ }
+
+ // Multiply the velocity by 1000 to match what was done in JPZ.
+ mOverscroll.setVelocity(x * 1000.0f, OverscrollEdgeEffect.AXIS_X);
+ mOverscroll.setVelocity(y * 1000.0f, OverscrollEdgeEffect.AXIS_Y);
+ }
+
+ /* package */ void updateOverscrollOffset(final float x, final float y) {
+ if (DEBUG) {
+ ThreadUtils.assertOnUiThread();
+ }
+
+ if (mOverscroll == null) {
+ return;
+ }
+
+ mOverscroll.setDistance(x, OverscrollEdgeEffect.AXIS_X);
+ mOverscroll.setDistance(y, OverscrollEdgeEffect.AXIS_Y);
+ }
+
+ /* package */ void onSelectionCaretDrag(final boolean dragging) {
+ if (DEBUG) {
+ ThreadUtils.assertOnUiThread();
+ }
+
+ if (mToolbar != null) {
+ mToolbar.setPinned(dragging, DynamicToolbarAnimator.PinReason.CARET_DRAG);
+ }
+ }
+
/* package */ void onMetricsChanged(final float scrollX, final float scrollY,
final float zoom) {
if (DEBUG) {
ThreadUtils.assertOnUiThread();
}
mViewportLeft = scrollX;
mViewportTop = scrollY;
@@ -413,18 +482,18 @@ public class LayerSession {
mClientTop = mTop + toolbarHeight;
mClientHeight = mHeight - toolbarHeight;
if (mAttachedCompositor) {
mCompositor.onBoundsChanged(mLeft, mClientTop, mWidth, mClientHeight);
}
- if (mCompositor.layerView != null) {
- mCompositor.layerView.onSizeChanged(mWidth, mHeight);
+ if (mOverscroll != null) {
+ mOverscroll.setSize(mWidth, mClientHeight);
}
}
/* package */ void onSurfaceChanged(final Surface surface, final int width,
final int height) {
ThreadUtils.assertOnUiThread();
mWidth = width;
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/LayerView.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/LayerView.java
@@ -47,19 +47,16 @@ import java.util.List;
public class LayerView extends FrameLayout {
private static final String LOGTAG = "GeckoLayerView";
private static AccessibilityManager sAccessibilityManager;
private PanZoomController mPanZoomController;
private FullScreenState mFullScreenState;
- /* This should only be modified on the Java UI thread. */
- private final Overscroll mOverscroll;
-
private int mDefaultClearColor = Color.WHITE;
/* package */ GetPixelsResult mGetPixelsResult;
private final List<DrawListener> mDrawListeners;
private void postCompositorMessage(final int message) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
@@ -81,29 +78,25 @@ public class LayerView extends FrameLayo
/* protected */ LayerSession mSession;
private LayerSession.Compositor mCompositor;
public LayerView(Context context, AttributeSet attrs) {
super(context, attrs);
mFullScreenState = FullScreenState.NONE;
- mOverscroll = new OverscrollEdgeEffect(this);
mDrawListeners = new ArrayList<DrawListener>();
}
public LayerView(Context context) {
this(context, null);
}
public void initializeView() {
mPanZoomController = PanZoomController.Factory.create(this);
- if (mOverscroll != null) {
- mPanZoomController.setOverscrollHandler(mOverscroll);
- }
}
/**
* MotionEventHelper dragAsync() robocop tests can instruct
* PanZoomController not to generate longpress events.
* This call comes in from a thread other than the UI thread.
* So dispatch to UI thread first to prevent assert in nsWindow.
*/
@@ -123,26 +116,16 @@ public class LayerView extends FrameLayo
protected void destroy() {
if (mPanZoomController != null) {
mPanZoomController.destroy();
}
}
@Override
- public void dispatchDraw(final Canvas canvas) {
- super.dispatchDraw(canvas);
-
- // We must have a layer client to get valid viewport metrics
- if (mOverscroll != null) {
- mOverscroll.draw(canvas);
- }
- }
-
- @Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
requestFocus();
}
if (!isCompositorReady()) {
// If gecko isn't loaded yet, don't try sending events to the
// native code because it's just going to crash
@@ -251,22 +234,16 @@ public class LayerView extends FrameLayo
}
}
@WrapForJNI(calledFrom = "ui")
private Object getCompositor() {
return isCompositorReady() ? mCompositor : null;
}
- /* package */ void onSizeChanged(int width, int height) {
- if (mOverscroll != null) {
- mOverscroll.setSize(width, height);
- }
- }
-
@RobocopTarget
public void addDrawListener(final DrawListener listener) {
if (!ThreadUtils.isOnUiThread()) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
addDrawListener(listener);
}
--- 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
@@ -25,17 +25,16 @@ import java.util.ArrayList;
class NativePanZoomController extends JNIObject implements PanZoomController {
private static final String LOGTAG = "GeckoNPZC";
private final float MAX_SCROLL;
private final LayerView mView;
private boolean mDestroyed;
- private Overscroll mOverscroll;
private float mPointerScrollFactor;
private long mLastDownTime;
private SynthesizedEventState mPointerState;
@WrapForJNI(calledFrom = "ui")
private native boolean handleMotionEvent(
int action, int actionIndex, long time, int metaState,
@@ -202,85 +201,26 @@ class NativePanZoomController extends JN
}
mDestroyed = true;
disposeNative();
}
@WrapForJNI(calledFrom = "ui", dispatchTo = "gecko_priority") @Override // JNIObject
protected native void disposeNative();
- @Override
- public void setOverscrollHandler(final Overscroll handler) {
- mOverscroll = handler;
- }
-
@WrapForJNI(stubName = "SetIsLongpressEnabled") // Called from test thread.
private native void nativeSetIsLongpressEnabled(boolean isLongpressEnabled);
@Override // PanZoomController
public void setIsLongpressEnabled(boolean isLongpressEnabled) {
if (!mDestroyed) {
nativeSetIsLongpressEnabled(isLongpressEnabled);
}
}
- @WrapForJNI
- private void updateOverscrollVelocity(final float x, final float y) {
- if (mOverscroll != null) {
- if (ThreadUtils.isOnUiThread() == true) {
- mOverscroll.setVelocity(x * 1000.0f, Overscroll.Axis.X);
- mOverscroll.setVelocity(y * 1000.0f, Overscroll.Axis.Y);
- } else {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- // Multiply the velocity by 1000 to match what was done in JPZ.
- mOverscroll.setVelocity(x * 1000.0f, Overscroll.Axis.X);
- mOverscroll.setVelocity(y * 1000.0f, Overscroll.Axis.Y);
- }
- });
- }
- }
- }
-
- @WrapForJNI
- private void updateOverscrollOffset(final float x, final float y) {
- if (mOverscroll != null) {
- if (ThreadUtils.isOnUiThread() == true) {
- mOverscroll.setDistance(x, Overscroll.Axis.X);
- mOverscroll.setDistance(y, Overscroll.Axis.Y);
- } else {
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- mOverscroll.setDistance(x, Overscroll.Axis.X);
- mOverscroll.setDistance(y, Overscroll.Axis.Y);
- }
- });
- }
- }
- }
-
- /**
- * Active SelectionCaretDrag requires DynamicToolbarAnimator to be pinned
- * to avoid unwanted scroll interactions.
- */
- @WrapForJNI(calledFrom = "gecko")
- private void onSelectionDragState(final boolean state) {
- final LayerView view = mView;
- ThreadUtils.postToUiThread(new Runnable() {
- @Override
- public void run() {
- if (view.mSession != null) {
- view.mSession.getDynamicToolbarAnimator()
- .setPinned(state, PinReason.CARET_DRAG);
- }
- }
- });
- }
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
// event synthesization. If somebody tries to use this ID for a
// synthesized touch event we'll throw an exception.
public static final int RESERVED_MOUSE_POINTER_ID = 100000;
deleted file mode 100644
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/Overscroll.java
+++ /dev/null
@@ -1,21 +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.Canvas;
-
-public interface Overscroll {
- // The axis to show overscroll on.
- public enum Axis {
- X,
- Y,
- };
-
- public void draw(final Canvas canvas);
- public void setSize(final int width, final int height);
- public void setVelocity(final float velocity, final Axis axis);
- public void setDistance(final float distance, final Axis axis);
-}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/OverscrollEdgeEffect.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/OverscrollEdgeEffect.java
@@ -1,135 +1,180 @@
/* -*- 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 org.mozilla.gecko.util.ThreadUtils;
+
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.os.Build;
+import android.view.View;
import android.widget.EdgeEffect;
import java.lang.reflect.Field;
-public class OverscrollEdgeEffect implements Overscroll {
+public class OverscrollEdgeEffect {
// Used to index particular edges in the edges array
private static final int TOP = 0;
private static final int BOTTOM = 1;
private static final int LEFT = 2;
private static final int RIGHT = 3;
+ /* package */ static final int AXIS_X = 0;
+ /* package */ static final int AXIS_Y = 1;
+
// All four edges of the screen
private final EdgeEffect[] mEdges = new EdgeEffect[4];
- // The view we're showing this overscroll on.
- private final LayerView mView;
+ private final LayerSession mSession;
+ private Runnable mInvalidationCallback;
+ private int mWidth;
+ private int mHeight;
+
+ /* package */ OverscrollEdgeEffect(final LayerSession session) {
+ mSession = session;
+ }
- public OverscrollEdgeEffect(final LayerView v) {
+ /**
+ * Set the theme to use for overscroll from a given Context.
+ *
+ * @param context Context to use for the overscroll theme.
+ */
+ public void setTheme(final Context context) {
+ ThreadUtils.assertOnUiThread();
+
+ final PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
Field paintField = null;
+
if (Build.VERSION.SDK_INT >= 21) {
try {
paintField = EdgeEffect.class.getDeclaredField("mPaint");
paintField.setAccessible(true);
} catch (NoSuchFieldException e) {
}
}
- mView = v;
- Context context = v.getContext();
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < mEdges.length; i++) {
mEdges[i] = new EdgeEffect(context);
+ if (paintField == null) {
+ continue;
+ }
+
try {
- if (paintField != null) {
- final Paint p = (Paint) paintField.get(mEdges[i]);
+ final Paint p = (Paint) paintField.get(mEdges[i]);
- // The Android EdgeEffect class uses a mode of SRC_ATOP here, which means it will only
- // draw the effect where there are non-transparent pixels in the destination. Since the LayerView
- // itself is fully transparent, it doesn't display at all. We need to use SRC instead.
- p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
- }
+ // The Android EdgeEffect class uses a mode of SRC_ATOP here, which means
+ // it will only draw the effect where there are non-transparent pixels in
+ // the destination. Since the LayerView itself is fully transparent, it
+ // doesn't display at all. We need to use SRC instead.
+ p.setXfermode(mode);
} catch (IllegalAccessException e) {
}
}
}
- @Override
- public void setSize(final int width, final int height) {
+ /**
+ * Set a Runnable that acts as a callback to invalidate the overscroll effect (for
+ * example, as a response to user fling for example). The Runnbale should schedule a
+ * future call to {@link #draw(Canvas)} as a result of the invalidation.
+ *
+ * @param runnable Invalidation Runnable.
+ * @see #getInvalidationCallback()
+ */
+ public void setInvalidationCallback(final Runnable runnable) {
+ ThreadUtils.assertOnUiThread();
+ mInvalidationCallback = runnable;
+ }
+
+ /**
+ * Get the current invalidatation Runnable.
+ *
+ * @return Invalidation Runnable.
+ * @see #setInvalidationCallback(Runnable)
+ */
+ public Runnable getInvalidationCallback() {
+ ThreadUtils.assertOnUiThread();
+ return mInvalidationCallback;
+ }
+
+ /* package */ void setSize(final int width, final int height) {
mEdges[LEFT].setSize(height, width);
mEdges[RIGHT].setSize(height, width);
mEdges[TOP].setSize(width, height);
mEdges[BOTTOM].setSize(width, height);
+
+ mWidth = width;
+ mHeight = height;
}
- private EdgeEffect getEdgeForAxisAndSide(final Axis axis, final float side) {
- if (axis == Axis.Y) {
+ private EdgeEffect getEdgeForAxisAndSide(final int axis, final float side) {
+ if (axis == AXIS_Y) {
if (side < 0) {
return mEdges[TOP];
} else {
return mEdges[BOTTOM];
}
} else {
if (side < 0) {
return mEdges[LEFT];
} else {
return mEdges[RIGHT];
}
}
}
- private void invalidate() {
- if (Build.VERSION.SDK_INT >= 16) {
- mView.postInvalidateOnAnimation();
- } else {
- mView.postInvalidateDelayed(10);
- }
- }
-
- @Override
- public void setVelocity(final float velocity, final Axis axis) {
+ /* package */ void setVelocity(final float velocity, final int axis) {
final EdgeEffect edge = getEdgeForAxisAndSide(axis, velocity);
// If we're showing overscroll already, start fading it out.
if (!edge.isFinished()) {
edge.onRelease();
} else {
// Otherwise, show an absorb effect
edge.onAbsorb((int)velocity);
}
- invalidate();
+ if (mInvalidationCallback != null) {
+ mInvalidationCallback.run();
+ }
}
- @Override
- public void setDistance(final float distance, final Axis axis) {
+ /* package */ void setDistance(final float distance, final int axis) {
// The first overscroll event often has zero distance. Throw it out
if (distance == 0.0f) {
return;
}
final EdgeEffect edge = getEdgeForAxisAndSide(axis, (int)distance);
- edge.onPull(distance / (axis == Axis.X ? mView.getWidth() : mView.getHeight()));
- invalidate();
+ edge.onPull(distance / (axis == AXIS_X ? mWidth : mHeight));
+
+ if (mInvalidationCallback != null) {
+ mInvalidationCallback.run();
+ }
}
- @Override
+ /**
+ * Draw the overscroll effect on a Canvas.
+ *
+ * @param canvas Canvas to draw on.
+ */
public void draw(final Canvas canvas) {
- if (mView.mSession == null) {
- return;
- }
+ ThreadUtils.assertOnUiThread();
final Rect pageRect = new Rect();
- mView.mSession.getSurfaceBounds(pageRect);
+ mSession.getSurfaceBounds(pageRect);
// If we're pulling an edge, or fading it out, draw!
boolean invalidate = false;
if (!mEdges[TOP].isFinished()) {
invalidate |= draw(mEdges[TOP], canvas, pageRect.left, pageRect.top, 0);
}
if (!mEdges[BOTTOM].isFinished()) {
@@ -140,18 +185,18 @@ public class OverscrollEdgeEffect implem
invalidate |= draw(mEdges[LEFT], canvas, pageRect.left, pageRect.bottom, 270);
}
if (!mEdges[RIGHT].isFinished()) {
invalidate |= draw(mEdges[RIGHT], canvas, pageRect.right, pageRect.top, 90);
}
// If the edge effect is animating off screen, invalidate.
- if (invalidate) {
- invalidate();
+ if (invalidate && mInvalidationCallback != null) {
+ mInvalidationCallback.run();
}
}
private static boolean draw(final EdgeEffect edge, final Canvas canvas, final float translateX, final float translateY, final float rotation) {
final int state = canvas.save();
canvas.translate(translateX, translateY);
canvas.rotate(rotation);
boolean invalidate = edge.draw(canvas);
--- 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
@@ -17,12 +17,10 @@ public interface PanZoomController {
}
}
public void destroy();
public boolean onTouchEvent(MotionEvent event);
public boolean onMotionEvent(MotionEvent event);
- public void setOverscrollHandler(final Overscroll controller);
-
public void setIsLongpressEnabled(boolean isLongpressEnabled);
}
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -175,16 +175,25 @@ namespace {
template<class Instance, class Impl> typename EnableIf<
jni::detail::NativePtrPicker<Impl>::value ==
jni::detail::OWNING, void>::Type
CallAttachNative(Instance aInstance, Impl* aImpl)
{
Impl::AttachNative(aInstance, UniquePtr<Impl>(aImpl));
}
+
+ template<class Lambda> bool
+ DispatchToUiThread(const char* aName, Lambda&& aLambda) {
+ if (RefPtr<nsThread> uiThread = GetAndroidUiThread()) {
+ uiThread->Dispatch(NS_NewRunnableFunction(aName, Move(aLambda)));
+ return true;
+ }
+ return false;
+ }
} // namespace
template<class Impl>
template<class Instance, typename... Args> void
nsWindow::NativePtr<Impl>::Attach(Instance aInstance, nsWindow* aWindow,
Args&&... aArgs)
{
MOZ_ASSERT(NS_IsMainThread());
@@ -733,31 +742,16 @@ public:
PostInputEvent([input, guid, blockId, status] (nsWindow* window) {
WidgetTouchEvent touchEvent = input.ToWidgetTouchEvent(window);
window->ProcessUntransformedAPZEvent(&touchEvent, guid,
blockId, status);
window->DispatchHitTest(touchEvent);
});
return true;
}
-
- void UpdateOverscrollVelocity(const float x, const float y)
- {
- mNPZC->UpdateOverscrollVelocity(x, y);
- }
-
- void UpdateOverscrollOffset(const float x, const float y)
- {
- mNPZC->UpdateOverscrollOffset(x, y);
- }
-
- void SetSelectionDragState(const bool aState)
- {
- mNPZC->OnSelectionDragState(aState);
- }
};
template<> const char
nsWindow::NativePtr<nsWindow::NPZCSupport>::sName[] = "NPZCSupport";
bool nsWindow::NPZCSupport::sNegateWheelScroll;
NS_IMPL_ISUPPORTS(nsWindow::AndroidView,
@@ -1997,35 +1991,67 @@ nsWindow::InitEvent(WidgetGUIEvent& even
}
event.mTime = PR_Now() / 1000;
}
void
nsWindow::UpdateOverscrollVelocity(const float aX, const float aY)
{
- if (NativePtr<NPZCSupport>::Locked npzcs{mNPZCSupport}) {
- npzcs->UpdateOverscrollVelocity(aX, aY);
+ if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
+ const auto& compositor = lvs->GetJavaCompositor();
+ if (AndroidBridge::IsJavaUiThread()) {
+ compositor->UpdateOverscrollVelocity(aX, aY);
+ return;
+ }
+
+ DispatchToUiThread(
+ "nsWindow::UpdateOverscrollVelocity",
+ [compositor = LayerSession::Compositor::GlobalRef(compositor),
+ aX, aY] {
+ compositor->UpdateOverscrollVelocity(aX, aY);
+ });
}
}
void
nsWindow::UpdateOverscrollOffset(const float aX, const float aY)
{
- if (NativePtr<NPZCSupport>::Locked npzcs{mNPZCSupport}) {
- npzcs->UpdateOverscrollOffset(aX, aY);
+ if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
+ const auto& compositor = lvs->GetJavaCompositor();
+ if (AndroidBridge::IsJavaUiThread()) {
+ compositor->UpdateOverscrollOffset(aX, aY);
+ return;
+ }
+
+ DispatchToUiThread(
+ "nsWindow::UpdateOverscrollOffset",
+ [compositor = LayerSession::Compositor::GlobalRef(compositor),
+ aX, aY] {
+ compositor->UpdateOverscrollOffset(aX, aY);
+ });
}
}
void
nsWindow::SetSelectionDragState(bool aState)
{
- if (NativePtr<NPZCSupport>::Locked npzcs{mNPZCSupport}) {
- npzcs->SetSelectionDragState(aState);
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (!mLayerViewSupport) {
+ return;
}
+
+ const auto& compositor = mLayerViewSupport->GetJavaCompositor();
+ DispatchToUiThread(
+ "nsWindow::SetSelectionDragState",
+ [compositor = LayerSession::Compositor::GlobalRef(compositor),
+ aState] {
+ compositor->OnSelectionCaretDrag(aState);
+ });
}
void *
nsWindow::GetNativeData(uint32_t aDataType)
{
switch (aDataType) {
// used by GLContextProviderEGL, nullptr is EGL_DEFAULT_DISPLAY
case NS_NATIVE_DISPLAY: