mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1238761 - Implement NativePanZoomController native methods; r=rbarker
This patch adds the NPZCSupport class to nsWindow and use it to implement the NPZC native methods that were implemented in AndroidJNI.cpp. For HandleMotionEvent, the code also includes a portion from AndroidJavaWrapper::MakeMultitouchEvent.
This commit is contained in:
parent
296a0a08cc
commit
919de6549b
@ -154,6 +154,7 @@ static bool sFailedToCreateGLContext = false;
|
||||
static const double SWIPE_MAX_PINCH_DELTA_INCHES = 0.4;
|
||||
static const double SWIPE_MIN_DISTANCE_INCHES = 0.6;
|
||||
|
||||
static Modifiers GetModifiers(int32_t metaState);
|
||||
|
||||
class nsWindow::GeckoViewSupport final
|
||||
: public GeckoView::Window::Natives<GeckoViewSupport>
|
||||
@ -245,17 +246,12 @@ public:
|
||||
, mIMESelectionChanged(false)
|
||||
, mIMETextChangedDuringFlush(false)
|
||||
{
|
||||
Reattach(aInstance);
|
||||
Base::AttachNative(aInstance, this);
|
||||
EditableBase::AttachNative(mEditable, this);
|
||||
}
|
||||
|
||||
~GeckoViewSupport();
|
||||
|
||||
void Reattach(const GeckoView::Window::LocalRef& aInstance)
|
||||
{
|
||||
Base::AttachNative(aInstance, this);
|
||||
}
|
||||
|
||||
using Base::DisposeNative;
|
||||
using EditableBase::DisposeNative;
|
||||
|
||||
@ -367,6 +363,282 @@ public:
|
||||
void OnImeUpdateComposition(int32_t aStart, int32_t aEnd);
|
||||
};
|
||||
|
||||
/**
|
||||
* NativePanZoomController handles its native calls on the UI thread, so make
|
||||
* it separate from GeckoViewSupport.
|
||||
*/
|
||||
class nsWindow::NPZCSupport final
|
||||
: public NativePanZoomController::Natives<NPZCSupport>
|
||||
{
|
||||
nsWindow* mWindow;
|
||||
// Lock for keeping mWindow alive when accessed off of the Gecko thread.
|
||||
Mutex mWindowLock;
|
||||
NativePanZoomController::GlobalRef mNPZC;
|
||||
|
||||
public:
|
||||
typedef NativePanZoomController::Natives<NPZCSupport> Base;
|
||||
|
||||
NPZCSupport(nsWindow* aWindow,
|
||||
const NativePanZoomController::LocalRef& aNPZC)
|
||||
: mWindow(aWindow)
|
||||
, mWindowLock("NPZCSupport")
|
||||
, mNPZC(aNPZC)
|
||||
{
|
||||
if (mWindow->mNPZCSupport) {
|
||||
mWindow->mNPZCSupport->DetachFromWindow();
|
||||
}
|
||||
mWindow->mNPZCSupport = this;
|
||||
}
|
||||
|
||||
~NPZCSupport()
|
||||
{}
|
||||
|
||||
using Base::AttachNative;
|
||||
|
||||
void DetachFromWindow()
|
||||
{
|
||||
// There are several considerations when shutting down NPZC. 1) The
|
||||
// Gecko thread may destroy NPZC at any time when nsWindow closes. 2)
|
||||
// There may be pending events on the Gecko thread when NPZC is
|
||||
// destroyed. 3) mWindow may not be available when the pending event
|
||||
// runs. 4) The UI thread may destroy NPZC at any time when GeckoView
|
||||
// is destroyed. 5) The UI thread may destroy NPZC at the same time as
|
||||
// Gecko thread trying to destroy NPZC. 6) There may be pending calls
|
||||
// on the UI thread when NPZC is destroyed. 7) mWindow may have been
|
||||
// cleared on the Gecko thread when the pending call happens on the UI
|
||||
// thread.
|
||||
//
|
||||
// 1) happens through DetachFromWindow, which first notifies the UI
|
||||
// thread through Destroy; Destroy then calls DisposeNative, which
|
||||
// finally disposes the native instance back on the Gecko thread. Using
|
||||
// Destroy to indirectly call DisposeNative here also solves 5), by
|
||||
// making everything go through the UI thread, avoiding contention.
|
||||
//
|
||||
// 2) and 3) are solved by clearing mWindow, which signals to the
|
||||
// pending event that we had shut down. In that case the event bails
|
||||
// and does not touch mWindow.
|
||||
//
|
||||
// 4) happens through DisposeNative directly. DetachFromWindow is not
|
||||
// called.
|
||||
//
|
||||
// 6) is solved by keeping a destroyed flag in the Java NPZC instance,
|
||||
// and only make a pending call if the destroyed flag is not set.
|
||||
//
|
||||
// 7) is solved by taking a lock whenever mWindow is modified on the
|
||||
// Gecko thread or accessed on the UI thread. That way, we don't
|
||||
// release mWindow until the UI thread is done using it, thus avoiding
|
||||
// the race condition.
|
||||
|
||||
typedef NativePanZoomController::GlobalRef NPZCRef;
|
||||
auto callDestroy = [] (const NPZCRef& npzc) {
|
||||
npzc->Destroy();
|
||||
};
|
||||
|
||||
NativePanZoomController::GlobalRef npzc = mNPZC;
|
||||
AndroidBridge::Bridge()->PostTaskToUiThread(NewRunnableFunction(
|
||||
static_cast<void(*)(const NPZCRef&)>(callDestroy),
|
||||
mozilla::Move(npzc)), 0);
|
||||
|
||||
// Signal to any pending calls on either Gecko or UI thread that NPZC
|
||||
// is being destroyed.
|
||||
MutexAutoLock lock(mWindowLock);
|
||||
mWindow->mNPZCSupport = nullptr;
|
||||
mWindow = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
void DisposeOnGeckoThread()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mWindow && mWindow->mNPZCSupport == this) {
|
||||
mWindow->mNPZCSupport = nullptr;
|
||||
}
|
||||
// Base::DisposeNative implicitly deletes 'this'.
|
||||
Base::DisposeNative(NativePanZoomController::LocalRef(
|
||||
jni::GetGeckoThreadEnv(), mNPZC));
|
||||
}
|
||||
|
||||
public:
|
||||
void DisposeNative()
|
||||
{
|
||||
// Capturing 'this' is okay because 'this' is owned by the Java
|
||||
// instance, it is alive until this lambda is run, and we make sure to
|
||||
// only call DisposeNative once.
|
||||
nsAppShell::PostEvent([this] {
|
||||
DisposeOnGeckoThread();
|
||||
});
|
||||
}
|
||||
|
||||
void AbortAnimation()
|
||||
{
|
||||
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
|
||||
|
||||
MutexAutoLock lock(mWindowLock);
|
||||
if (!mWindow) {
|
||||
// We already shut down.
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<APZCTreeManager> controller = mWindow->mAPZC;
|
||||
RefPtr<CompositorParent> compositor = mWindow->mCompositorParent;
|
||||
if (controller && compositor) {
|
||||
// TODO: Pass in correct values for presShellId and viewId.
|
||||
controller->CancelAnimation(ScrollableLayerGuid(
|
||||
compositor->RootLayerTreeId(), 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void SetIsLongpressEnabled(bool aIsLongpressEnabled)
|
||||
{
|
||||
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
|
||||
|
||||
APZCTreeManager::SetLongTapEnabled(aIsLongpressEnabled);
|
||||
}
|
||||
|
||||
bool HandleMotionEvent(const NativePanZoomController::LocalRef& aInstance,
|
||||
int32_t aAction, int32_t aActionIndex,
|
||||
int64_t aTime, int32_t aMetaState,
|
||||
jni::IntArray::Param aPointerId,
|
||||
jni::FloatArray::Param aX,
|
||||
jni::FloatArray::Param aY,
|
||||
jni::FloatArray::Param aOrientation,
|
||||
jni::FloatArray::Param aPressure,
|
||||
jni::FloatArray::Param aToolMajor,
|
||||
jni::FloatArray::Param aToolMinor)
|
||||
{
|
||||
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
|
||||
|
||||
MutexAutoLock lock(mWindowLock);
|
||||
if (!mWindow) {
|
||||
// We already shut down.
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<APZCTreeManager> controller = mWindow->mAPZC;
|
||||
if (!controller) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsTArray<int32_t> pointerId(aPointerId);
|
||||
MultiTouchInput::MultiTouchType type;
|
||||
size_t startIndex = 0;
|
||||
size_t endIndex = pointerId.Length();
|
||||
|
||||
switch (aAction) {
|
||||
case AndroidMotionEvent::ACTION_DOWN:
|
||||
case AndroidMotionEvent::ACTION_POINTER_DOWN:
|
||||
type = MultiTouchInput::MULTITOUCH_START;
|
||||
break;
|
||||
case AndroidMotionEvent::ACTION_MOVE:
|
||||
type = MultiTouchInput::MULTITOUCH_MOVE;
|
||||
break;
|
||||
case AndroidMotionEvent::ACTION_UP:
|
||||
case AndroidMotionEvent::ACTION_POINTER_UP:
|
||||
// for pointer-up events we only want the data from
|
||||
// the one pointer that went up
|
||||
type = MultiTouchInput::MULTITOUCH_END;
|
||||
startIndex = aActionIndex;
|
||||
endIndex = aActionIndex + 1;
|
||||
break;
|
||||
case AndroidMotionEvent::ACTION_OUTSIDE:
|
||||
case AndroidMotionEvent::ACTION_CANCEL:
|
||||
type = MultiTouchInput::MULTITOUCH_CANCEL;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
MultiTouchInput input(type, aTime, TimeStamp(), 0);
|
||||
input.modifiers = GetModifiers(aMetaState);
|
||||
input.mTouches.SetCapacity(endIndex - startIndex);
|
||||
|
||||
nsTArray<float> x(aX);
|
||||
nsTArray<float> y(aY);
|
||||
nsTArray<float> orientation(aOrientation);
|
||||
nsTArray<float> pressure(aPressure);
|
||||
nsTArray<float> toolMajor(aToolMajor);
|
||||
nsTArray<float> toolMinor(aToolMinor);
|
||||
|
||||
MOZ_ASSERT(pointerId.Length() == x.Length());
|
||||
MOZ_ASSERT(pointerId.Length() == y.Length());
|
||||
MOZ_ASSERT(pointerId.Length() == orientation.Length());
|
||||
MOZ_ASSERT(pointerId.Length() == pressure.Length());
|
||||
MOZ_ASSERT(pointerId.Length() == toolMajor.Length());
|
||||
MOZ_ASSERT(pointerId.Length() == toolMinor.Length());
|
||||
|
||||
const nsIntPoint& offset =
|
||||
mWindow->WidgetToScreenOffset().ToUnknownPoint();
|
||||
|
||||
for (size_t i = startIndex; i < endIndex; i++) {
|
||||
|
||||
float orien = orientation[i] * 180.0f / M_PI;
|
||||
// w3c touchevents spec does not allow orientations == 90
|
||||
// this shifts it to -90, which will be shifted to zero below
|
||||
if (orien >= 90.0) {
|
||||
orien -= 180.0f;
|
||||
}
|
||||
|
||||
nsIntPoint point = nsIntPoint(int32_t(floorf(x[i])),
|
||||
int32_t(floorf(y[i]))) - offset;
|
||||
|
||||
// w3c touchevent radii are given with an orientation between 0 and
|
||||
// 90. The radii are found by removing the orientation and
|
||||
// measuring the x and y radii of the resulting ellipse. For
|
||||
// Android orientations >= 0 and < 90, use the y radius as the
|
||||
// major radius, and x as the minor radius. However, for an
|
||||
// orientation < 0, we have to shift the orientation by adding 90,
|
||||
// and reverse which radius is major and minor.
|
||||
gfx::Size radius;
|
||||
if (orien < 0.0f) {
|
||||
orien += 90.0f;
|
||||
radius = gfx::Size(int32_t(toolMajor[i] / 2.0f),
|
||||
int32_t(toolMinor[i] / 2.0f));
|
||||
} else {
|
||||
radius = gfx::Size(int32_t(toolMinor[i] / 2.0f),
|
||||
int32_t(toolMajor[i] / 2.0f));
|
||||
}
|
||||
|
||||
input.mTouches.AppendElement(SingleTouchData(
|
||||
pointerId[i], ScreenIntPoint::FromUnknownPoint(point),
|
||||
ScreenSize::FromUnknownSize(radius), orien, pressure[i]));
|
||||
}
|
||||
|
||||
ScrollableLayerGuid guid;
|
||||
uint64_t blockId;
|
||||
nsEventStatus status =
|
||||
controller->ReceiveInputEvent(input, &guid, &blockId);
|
||||
|
||||
if (status == nsEventStatus_eConsumeNoDefault) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Dispatch APZ input event on Gecko thread.
|
||||
NativePanZoomController::GlobalRef npzc = mNPZC;
|
||||
nsAppShell::PostEvent([npzc, input, guid, blockId, status] {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
JNIEnv* const env = jni::GetGeckoThreadEnv();
|
||||
NPZCSupport* npzcSupport = GetNative(
|
||||
NativePanZoomController::LocalRef(env, npzc));
|
||||
|
||||
if (!npzcSupport || !npzcSupport->mWindow) {
|
||||
// We already shut down.
|
||||
env->ExceptionClear();
|
||||
return;
|
||||
}
|
||||
|
||||
nsWindow* const window = npzcSupport->mWindow;
|
||||
window->UserActivity();
|
||||
WidgetTouchEvent touchEvent = input.ToWidgetTouchEvent(window);
|
||||
window->ProcessUntransformedAPZEvent(&touchEvent, guid,
|
||||
blockId, status);
|
||||
window->DispatchHitTest(touchEvent);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* GLController has some unique requirements for its native calls, so make it
|
||||
* separate from GeckoViewSupport.
|
||||
@ -465,7 +737,7 @@ public:
|
||||
, mGLController(aInstance)
|
||||
, mCompositorPaused(true)
|
||||
{
|
||||
Reattach(aInstance);
|
||||
Base::AttachNative(aInstance, this);
|
||||
}
|
||||
|
||||
~GLControllerSupport()
|
||||
@ -473,11 +745,6 @@ public:
|
||||
mGLController->Destroy();
|
||||
}
|
||||
|
||||
void Reattach(const GLController::LocalRef& aInstance)
|
||||
{
|
||||
Base::AttachNative(aInstance, this);
|
||||
}
|
||||
|
||||
const GeckoLayerClient::Ref& GetLayerClient() const
|
||||
{
|
||||
return mLayerClient;
|
||||
@ -711,6 +978,7 @@ nsWindow::InitNatives()
|
||||
nsWindow::GeckoViewSupport::Base::Init();
|
||||
nsWindow::GeckoViewSupport::EditableBase::Init();
|
||||
nsWindow::GLControllerSupport::Init();
|
||||
nsWindow::NPZCSupport::Init();
|
||||
}
|
||||
|
||||
nsWindow*
|
||||
@ -752,6 +1020,7 @@ nsWindow::DumpWindows(const nsTArray<nsWindow*>& wins, int indent)
|
||||
}
|
||||
|
||||
nsWindow::nsWindow() :
|
||||
mNPZCSupport(nullptr),
|
||||
mIsVisible(false),
|
||||
mParent(nullptr),
|
||||
mAwaitingFullScreen(false),
|
||||
|
@ -57,6 +57,11 @@ private:
|
||||
// Object that implements native GLController calls.
|
||||
mozilla::UniquePtr<GLControllerSupport> mGLControllerSupport;
|
||||
|
||||
class NPZCSupport;
|
||||
// Object that implements native NativePanZoomController calls.
|
||||
// Owned by the Java NativePanZoomController instance.
|
||||
NPZCSupport* mNPZCSupport;
|
||||
|
||||
public:
|
||||
static void OnGlobalAndroidEvent(mozilla::AndroidGeckoEvent *ae);
|
||||
static mozilla::gfx::IntSize GetAndroidScreenBounds();
|
||||
|
Loading…
Reference in New Issue
Block a user