2010-11-24 18:22:40 +00:00
|
|
|
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
|
2016-09-29 06:23:56 +00:00
|
|
|
* vim: set sw=4 ts=4 expandtab:
|
2012-05-21 11:12:37 +00:00
|
|
|
* 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/. */
|
2010-06-03 20:56:36 +00:00
|
|
|
|
|
|
|
#include <android/log.h>
|
2016-08-19 21:17:24 +00:00
|
|
|
#include <android/native_window.h>
|
|
|
|
#include <android/native_window_jni.h>
|
2010-08-26 05:52:08 +00:00
|
|
|
#include <math.h>
|
2011-12-21 19:05:23 +00:00
|
|
|
#include <unistd.h>
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2015-03-31 22:20:27 +00:00
|
|
|
#include "mozilla/IMEStateManager.h"
|
2013-09-25 11:21:20 +00:00
|
|
|
#include "mozilla/MiscEvents.h"
|
2013-09-25 11:21:18 +00:00
|
|
|
#include "mozilla/MouseEvents.h"
|
2015-03-31 22:20:27 +00:00
|
|
|
#include "mozilla/TextComposition.h"
|
2013-09-25 11:21:19 +00:00
|
|
|
#include "mozilla/TextEvents.h"
|
2013-09-25 11:21:16 +00:00
|
|
|
#include "mozilla/TouchEvents.h"
|
2015-10-22 21:45:46 +00:00
|
|
|
#include "mozilla/TypeTraits.h"
|
2015-09-21 14:13:32 +00:00
|
|
|
#include "mozilla/WeakPtr.h"
|
2013-09-25 11:21:16 +00:00
|
|
|
|
2010-11-24 18:22:40 +00:00
|
|
|
#include "mozilla/dom/ContentParent.h"
|
|
|
|
#include "mozilla/dom/ContentChild.h"
|
2016-08-23 04:09:32 +00:00
|
|
|
#include "mozilla/Unused.h"
|
2011-06-07 07:38:00 +00:00
|
|
|
#include "mozilla/Preferences.h"
|
2012-02-27 19:31:29 +00:00
|
|
|
#include "mozilla/layers/RenderTrace.h"
|
2013-01-15 12:22:03 +00:00
|
|
|
#include <algorithm>
|
2010-11-24 18:22:40 +00:00
|
|
|
|
|
|
|
using mozilla::dom::ContentParent;
|
|
|
|
using mozilla::dom::ContentChild;
|
2015-11-02 05:53:26 +00:00
|
|
|
using mozilla::Unused;
|
2010-11-24 18:22:40 +00:00
|
|
|
|
2010-06-03 20:56:36 +00:00
|
|
|
#include "nsWindow.h"
|
2015-09-21 14:13:32 +00:00
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
#include "nsIBaseWindow.h"
|
2016-07-21 01:43:34 +00:00
|
|
|
#include "nsIDOMChromeWindow.h"
|
2010-11-24 18:22:40 +00:00
|
|
|
#include "nsIObserverService.h"
|
2015-09-21 14:13:32 +00:00
|
|
|
#include "nsISelection.h"
|
|
|
|
#include "nsISupportsPrimitives.h"
|
2012-08-15 18:52:42 +00:00
|
|
|
#include "nsIWidgetListener.h"
|
2015-09-21 14:13:32 +00:00
|
|
|
#include "nsIWindowWatcher.h"
|
2015-10-22 21:45:46 +00:00
|
|
|
#include "nsIXULWindow.h"
|
2015-09-21 14:13:32 +00:00
|
|
|
|
|
|
|
#include "nsAppShell.h"
|
|
|
|
#include "nsFocusManager.h"
|
|
|
|
#include "nsIdleService.h"
|
|
|
|
#include "nsLayoutUtils.h"
|
2013-01-05 03:12:24 +00:00
|
|
|
#include "nsViewManager.h"
|
2015-09-21 14:13:32 +00:00
|
|
|
|
|
|
|
#include "WidgetUtils.h"
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2010-08-26 05:52:08 +00:00
|
|
|
#include "nsIDOMSimpleGestureEvent.h"
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2011-10-14 18:11:22 +00:00
|
|
|
#include "nsGkAtoms.h"
|
2010-06-03 20:56:36 +00:00
|
|
|
#include "nsWidgetsCID.h"
|
|
|
|
#include "nsGfxCIID.h"
|
|
|
|
|
|
|
|
#include "gfxContext.h"
|
|
|
|
|
2010-06-26 00:52:37 +00:00
|
|
|
#include "Layers.h"
|
2013-04-25 22:25:33 +00:00
|
|
|
#include "mozilla/layers/LayerManagerComposite.h"
|
2013-04-28 06:46:30 +00:00
|
|
|
#include "mozilla/layers/AsyncCompositionManager.h"
|
2015-11-13 20:10:52 +00:00
|
|
|
#include "mozilla/layers/APZEventState.h"
|
2015-04-20 20:16:17 +00:00
|
|
|
#include "mozilla/layers/APZThreadUtils.h"
|
2016-07-20 11:37:00 +00:00
|
|
|
#include "mozilla/layers/IAPZCTreeManager.h"
|
2010-06-26 00:52:37 +00:00
|
|
|
#include "GLContext.h"
|
|
|
|
#include "GLContextProvider.h"
|
2014-01-07 20:02:18 +00:00
|
|
|
#include "ScopedGLHelpers.h"
|
|
|
|
#include "mozilla/layers/CompositorOGL.h"
|
2015-04-25 02:26:51 +00:00
|
|
|
#include "AndroidContentController.h"
|
2010-06-26 00:52:37 +00:00
|
|
|
|
2010-06-03 20:56:36 +00:00
|
|
|
#include "nsTArray.h"
|
|
|
|
|
|
|
|
#include "AndroidBridge.h"
|
2013-11-12 18:41:01 +00:00
|
|
|
#include "AndroidBridgeUtilities.h"
|
2016-11-30 22:59:57 +00:00
|
|
|
#include "AndroidUiThread.h"
|
2012-04-19 17:49:31 +00:00
|
|
|
#include "android_npapi.h"
|
2016-09-16 19:13:48 +00:00
|
|
|
#include "FennecJNINatives.h"
|
2015-09-21 14:13:32 +00:00
|
|
|
#include "GeneratedJNINatives.h"
|
2015-10-22 21:45:46 +00:00
|
|
|
#include "KeyEvent.h"
|
2016-01-15 18:05:45 +00:00
|
|
|
#include "MotionEvent.h"
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2011-10-11 00:40:17 +00:00
|
|
|
#include "imgIEncoder.h"
|
|
|
|
|
2013-09-23 17:25:00 +00:00
|
|
|
#include "nsString.h"
|
2013-09-23 13:33:31 +00:00
|
|
|
#include "GeckoProfiler.h" // For PROFILER_LABEL
|
2014-02-05 07:43:59 +00:00
|
|
|
#include "nsIXULRuntime.h"
|
2015-11-22 09:44:33 +00:00
|
|
|
#include "nsPrintfCString.h"
|
2011-11-10 01:39:29 +00:00
|
|
|
|
2010-06-03 20:56:36 +00:00
|
|
|
using namespace mozilla;
|
2013-04-05 08:49:00 +00:00
|
|
|
using namespace mozilla::dom;
|
2016-07-21 06:07:12 +00:00
|
|
|
using namespace mozilla::layers;
|
2016-07-21 17:49:04 +00:00
|
|
|
using namespace mozilla::java;
|
|
|
|
using namespace mozilla::widget;
|
2010-06-03 20:56:36 +00:00
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
|
|
|
|
|
2016-03-22 18:08:38 +00:00
|
|
|
#include "mozilla/layers/CompositorBridgeChild.h"
|
2016-05-18 05:33:22 +00:00
|
|
|
#include "mozilla/layers/CompositorSession.h"
|
2013-04-24 18:42:40 +00:00
|
|
|
#include "mozilla/layers/LayerTransactionParent.h"
|
2017-01-05 19:11:41 +00:00
|
|
|
#include "mozilla/layers/UiCompositorControllerChild.h"
|
2014-04-29 17:31:06 +00:00
|
|
|
#include "mozilla/Services.h"
|
2011-12-21 19:05:23 +00:00
|
|
|
#include "nsThreadUtils.h"
|
|
|
|
|
2017-02-20 03:34:44 +00:00
|
|
|
static TimeStamp
|
|
|
|
GetEventTimeStamp(int64_t aEventTime)
|
|
|
|
{
|
|
|
|
// Android's event time is SystemClock.uptimeMillis that is counted in ms
|
|
|
|
// since OS was booted.
|
|
|
|
// (https://developer.android.com/reference/android/os/SystemClock.html)
|
|
|
|
// and this SystemClock.uptimeMillis uses SYSTEM_TIME_MONOTONIC.
|
|
|
|
// Our posix implemententaion of TimeStamp::Now uses SYSTEM_TIME_MONOTONIC
|
|
|
|
// too. Due to same implementation, we can use this via FromSystemTime.
|
|
|
|
int64_t tick =
|
|
|
|
BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aEventTime);
|
|
|
|
return TimeStamp::FromSystemTime(tick);
|
|
|
|
}
|
|
|
|
|
2010-06-03 20:56:36 +00:00
|
|
|
// All the toplevel windows that have been created; these are in
|
2016-02-01 22:38:14 +00:00
|
|
|
// stacking order, so the window at gTopLevelWindows[0] is the topmost
|
2010-06-03 20:56:36 +00:00
|
|
|
// one.
|
|
|
|
static nsTArray<nsWindow*> gTopLevelWindows;
|
|
|
|
|
2010-09-08 22:19:11 +00:00
|
|
|
static bool sFailedToCreateGLContext = false;
|
2010-08-26 05:52:08 +00:00
|
|
|
|
2010-11-18 17:18:31 +00:00
|
|
|
// Multitouch swipe thresholds in inches
|
|
|
|
static const double SWIPE_MAX_PINCH_DELTA_INCHES = 0.4;
|
|
|
|
static const double SWIPE_MIN_DISTANCE_INCHES = 0.6;
|
2010-06-26 00:52:37 +00:00
|
|
|
|
2016-07-20 07:19:05 +00:00
|
|
|
// Sync with GeckoEditableView class
|
|
|
|
static const int IME_MONITOR_CURSOR_ONE_SHOT = 1;
|
|
|
|
static const int IME_MONITOR_CURSOR_START_MONITOR = 2;
|
|
|
|
static const int IME_MONITOR_CURSOR_END_MONITOR = 3;
|
|
|
|
|
2016-01-15 18:05:45 +00:00
|
|
|
static Modifiers GetModifiers(int32_t metaState);
|
2015-09-21 14:13:32 +00:00
|
|
|
|
2016-05-05 15:39:02 +00:00
|
|
|
template<typename Lambda, bool IsStatic, typename InstanceType, class Impl>
|
|
|
|
class nsWindow::WindowEvent : public nsAppShell::LambdaEvent<Lambda>
|
2015-09-21 14:13:32 +00:00
|
|
|
{
|
2016-05-05 15:39:02 +00:00
|
|
|
typedef nsAppShell::Event Event;
|
|
|
|
typedef nsAppShell::LambdaEvent<Lambda> Base;
|
2015-09-21 14:13:32 +00:00
|
|
|
|
2016-05-05 15:39:02 +00:00
|
|
|
bool IsStaleCall()
|
2015-10-22 21:45:46 +00:00
|
|
|
{
|
2016-05-05 15:39:02 +00:00
|
|
|
if (IsStatic) {
|
|
|
|
// Static calls are never stale.
|
|
|
|
return false;
|
|
|
|
}
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2016-05-05 15:39:02 +00:00
|
|
|
JNIEnv* const env = mozilla::jni::GetEnvForThread();
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2016-05-05 15:39:02 +00:00
|
|
|
const auto natives = reinterpret_cast<mozilla::WeakPtr<Impl>*>(
|
|
|
|
jni::GetNativeHandle(env, mInstance.Get()));
|
|
|
|
MOZ_CATCH_JNI_EXCEPTION(env);
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2016-05-05 15:39:02 +00:00
|
|
|
// The call is stale if the nsWindow has been destroyed on the
|
|
|
|
// Gecko side, but the Java object is still attached to it through
|
|
|
|
// a weak pointer. Stale calls should be discarded. Note that it's
|
|
|
|
// an error if natives is nullptr here; we return false but the
|
|
|
|
// native call will throw an error.
|
|
|
|
return natives && !natives->get();
|
|
|
|
}
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2016-05-05 15:39:02 +00:00
|
|
|
const InstanceType mInstance;
|
|
|
|
const Event::Type mEventType;
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2016-05-05 15:39:02 +00:00
|
|
|
public:
|
|
|
|
WindowEvent(Lambda&& aLambda,
|
|
|
|
InstanceType&& aInstance,
|
|
|
|
Event::Type aEventType = Event::Type::kGeneralActivity)
|
|
|
|
: Base(mozilla::Move(aLambda))
|
|
|
|
, mInstance(mozilla::Move(aInstance))
|
|
|
|
, mEventType(aEventType)
|
|
|
|
{}
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2016-05-05 15:39:02 +00:00
|
|
|
WindowEvent(Lambda&& aLambda,
|
|
|
|
Event::Type aEventType = Event::Type::kGeneralActivity)
|
|
|
|
: Base(mozilla::Move(aLambda))
|
|
|
|
, mInstance(Base::lambda.GetThisArg())
|
|
|
|
, mEventType(aEventType)
|
|
|
|
{}
|
2015-10-22 21:45:47 +00:00
|
|
|
|
2016-05-05 15:39:02 +00:00
|
|
|
void Run() override
|
|
|
|
{
|
|
|
|
if (!IsStaleCall()) {
|
|
|
|
return Base::Run();
|
2015-10-22 21:45:47 +00:00
|
|
|
}
|
2016-05-05 15:39:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Event::Type ActivityType() const override
|
|
|
|
{
|
|
|
|
return mEventType;
|
|
|
|
}
|
|
|
|
};
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
template<class Impl>
|
|
|
|
template<class Instance, typename... Args> void
|
|
|
|
nsWindow::NativePtr<Impl>::Attach(Instance aInstance, nsWindow* aWindow,
|
|
|
|
Args&&... aArgs)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(!mPtr && !mImpl);
|
|
|
|
|
|
|
|
auto impl = mozilla::MakeUnique<Impl>(
|
|
|
|
this, aWindow, mozilla::Forward<Args>(aArgs)...);
|
|
|
|
mImpl = impl.get();
|
|
|
|
|
|
|
|
Impl::AttachNative(aInstance, mozilla::Move(impl));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class Impl> void
|
|
|
|
nsWindow::NativePtr<Impl>::Detach()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(mPtr && mImpl);
|
|
|
|
|
|
|
|
mImpl->OnDetach();
|
|
|
|
{
|
|
|
|
Locked implLock(*this);
|
|
|
|
mImpl = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
typename WindowPtr<Impl>::Locked lock(*mPtr);
|
|
|
|
mPtr->mWindow = nullptr;
|
|
|
|
mPtr->mPtr = nullptr;
|
|
|
|
mPtr = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class Impl>
|
|
|
|
class nsWindow::NativePtr<Impl>::Locked final : private MutexAutoLock
|
|
|
|
{
|
|
|
|
Impl* const mImpl;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Locked(NativePtr<Impl>& aPtr)
|
|
|
|
: MutexAutoLock(aPtr.mImplLock)
|
|
|
|
, mImpl(aPtr.mImpl)
|
|
|
|
{}
|
|
|
|
|
|
|
|
operator Impl*() const { return mImpl; }
|
|
|
|
Impl* operator->() const { return mImpl; }
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class Impl>
|
|
|
|
class nsWindow::WindowPtr final
|
|
|
|
{
|
|
|
|
friend NativePtr<Impl>;
|
|
|
|
|
|
|
|
NativePtr<Impl>* mPtr;
|
|
|
|
nsWindow* mWindow;
|
|
|
|
Mutex mWindowLock;
|
|
|
|
|
|
|
|
public:
|
|
|
|
class Locked final : private MutexAutoLock
|
|
|
|
{
|
|
|
|
nsWindow* const mWindow;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Locked(WindowPtr<Impl>& aPtr)
|
|
|
|
: MutexAutoLock(aPtr.mWindowLock)
|
|
|
|
, mWindow(aPtr.mWindow)
|
|
|
|
{}
|
|
|
|
|
|
|
|
operator nsWindow*() const { return mWindow; }
|
|
|
|
nsWindow* operator->() const { return mWindow; }
|
|
|
|
};
|
|
|
|
|
|
|
|
WindowPtr(NativePtr<Impl>* aPtr, nsWindow* aWindow)
|
|
|
|
: mPtr(aPtr)
|
|
|
|
, mWindow(aWindow)
|
|
|
|
, mWindowLock(NativePtr<Impl>::sName)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mPtr->mPtr = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
~WindowPtr()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (!mPtr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mPtr->mPtr = nullptr;
|
|
|
|
mPtr->mImpl = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
operator nsWindow*() const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
return mWindow;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsWindow* operator->() const { return operator nsWindow*(); }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-05-05 15:39:02 +00:00
|
|
|
class nsWindow::GeckoViewSupport final
|
|
|
|
: public GeckoView::Window::Natives<GeckoViewSupport>
|
|
|
|
, public GeckoEditable::Natives<GeckoViewSupport>
|
|
|
|
, public SupportsWeakPtr<GeckoViewSupport>
|
|
|
|
{
|
|
|
|
nsWindow& window;
|
|
|
|
|
|
|
|
public:
|
2015-12-24 03:03:34 +00:00
|
|
|
typedef GeckoView::Window::Natives<GeckoViewSupport> Base;
|
|
|
|
typedef GeckoEditable::Natives<GeckoViewSupport> EditableBase;
|
Bug 1307820 - Implement per-GeckoView messaging; r=snorp r=sebastian
Bug 1307820 - 1a. Move GeckoApp EventDispatcher to GeckoView; r=snorp
Make it a GeckoView-specific EventDispatcher instead of
GeckoApp-specific, so that GeckoView consumers can benefit from a
per-view EventDispatcher. In addition, a few events like Gecko:Ready are
moved back to the global EventDispatcher because that makes more sense.
Bug 1307820 - 1b. Don't use GeckoApp EventDispatcher during inflation; r=snorp
During layout inflation, we don't yet have GeckoView and therefore the
GeckoView EventDispatcher, so we should not register events until later,
typically during onAttachedToWindow.
Bug 1307820 - 2. Introduce GeckoBundle; r=snorp
The Android Bundle class has several disadvantages when used for holding
structured data from JS.
The most obvious one is the differentiation between int and double,
which doesn't exist in JS. So when a JS number is converted to either a
Bundle int or double, we run the risk of making a wrong conversion,
resulting in a type mismatch exception when Java uses the Bundle. This
extends to number arrays from JS.
There is one more gotcha when using arrays. When we receive an empty
array from JS, there is no way for us to determine the type of the
array, because even empty arrays in Java have types. We are forced to
pick an arbitrary type like boolean[], which can easily result in a type
mismatch exception when using the array on the Java side.
In addition, Bundle is fairly cumbersome, and we cannot access the inner
structures of Bundle from Java or JNI, making it harder to use.
With these factors in mind, this patch introduces GeckoBundle as a
better choice for Gecko/Java communication. It is almost fully
API-compatible with the Android Bundle; only the Bundle array methods
are different. It resolves the numbers problem by performing conversions
if necessary, and it is a lot more lightweight than Bundle.
Bug 1307820 - 3. Convert BundleEventListener to use GeckoBundle; r=snorp
Convert BundleEventListener from using Bundle to using GeckoBundle.
Because NativeJSContainer still only supports Bundle, we do an extra
conversion when sending Bundle messages, but eventually, as we eliminate
the use of NativeJSContainer, that will go away as well.
Bug 1307820 - 4. Introduce EventDispatcher interfaces; r=snorp
Introduce several new XPCOM interfaces for the new EventDispatcher API,
these interfaces are mostly mirrored after their Java counterparts.
* nsIAndroidEventDispatcher is the main interface for
registering/unregistering listeners and for dispatching events from
JS/C++.
* nsIAndroidEventListener is the interface that JS/C++ clients implement
to receive events.
* nsIAndroidEventCallback is the interface that JS/C++ clients implement
to receive responses from dispatched events.
* nsIAndroidView is the new interface that every window receives
that is specific to the window/GeckoView pair. It is passed to chrome
scripts through window arguments.
Bug 1307820 - 5. Remove EventDispatcher references from gfx code; r=snorp
EventDispatcher was used for JPZC, but NPZC doesn't use it anymore.
Bug 1307820 - 6. General JNI template improvements; r=snorp
This patch includes several improvements to the JNI templates.
* Context::RawClassRef is removed to avoid misuse, as Context::ClassRef
should be used instead.
* Fix a compile error, in certain usages, in the DisposeNative overload
in NativeStub.
* Add Ref::IsInstanceOf and Context::IsInstanceOf to mirror the
JNIEnv::IsInstanceOf call.
* Add Ref::operator* and Context::operator* to provide an easy way to
get a Context object.
* Add built-in declarations for boxed Java objects (e.g. Boolean,
Integer, etc).
* Add ObjectArray::New for creating new object arrays of specific types.
* Add lvalue qualifiers to LocalRef::operator= and GlobalRef::operator=,
to prevent accidentally assigning to rvalues. (e.g.
`objectArray->GetElement(0) = newObject;`, which won't work as intended.)
Bug 1307820 - 7. Support ownership through RefPtr for native JNI objects; r=snorp
In addition to direct ownership and weak pointer ownership, add a third
ownership model where a native JNI object owns a RefPtr that holds a
strong reference to the actual C++ object. This ownership model works
well with ref-counted objects such as XPCOM objects, and is activated
through the presence of public members AddRef() and Release() in the C++
object.
Bug 1307820 - 8. Implement Gecko-side EventDispatcher; r=snorp
Add a skeletal implementation of EventDispatcher on the Gecko side.
Each widget::EventDispatcher will be associated with a Java
EventDispatcher, so events can be dispatched from Gecko to Java and vice
versa. AndroidBridge and nsWindow will implement
nsIAndroidEventDispatcher through widget::EventDispatcher.
Other patches will add more complete functionality such as
GeckoBundle/JSObject translation and support for callbacks.
Bug 1307820 - 9. Implement dispatching between Gecko/Java; r=snorp
Implement translation between JSObject and GeckoBundle, and use that for
dispatching events from Gecko to Java and vice versa.
Bug 1307820 - 10. Implement callback support; r=snorp
Implement callback support for both Gecko-to-Java events and
Java-to-Gecko events.
For Gecko-to-Java, we translate nsIAndroidEventCallback to a Java
EventCallback through NativeCallbackDelegate and pass it to the Java
listener.
For Java-to-Gecko, we translate EventCallback to a
nsIAndroidEventCallback through JavaCallbackDelegate and pass it to the
Gecko listener. There is another JavaCallbackDelegate on the Java side
that redirects the callback to a particular thread. For example, if the
event was dispatched from the UI thread, we make sure the callback
happens on the UI thread as well.
Bug 1307820 - 11. Add BundleEventListener support for Gecko thread; r=snorp
Add support for BundleEventListener on the Gecko thread, so that we can
use it to replace any existing GeckoEventListener or NativeEventListener
implementations that require the listener be run synchronously on the
Gecko thread.
Bug 1307820 - 12. Add global EventDispatcher in AndroidBridge; r=snorp
Add an instance of EventDispatcher to AndroidBridge to act as a global
event dispatcher.
Bug 1307820 - 13. Add per-nsWindow EventDispatcher; r=snorp
Add an instance of EventDispatcher to each nsWindow through an
AndroidView object, which implements nsIAndroidView. The nsIAndroidView
is passed to the chrome script through the window argument when opening
the window.
Bug 1307820 - 14. Update auto-generated bindings; r=me
Bug 1307820 - 15. Update testEventDispatcher; r=snorp
Update testEventDispatcher to include new functionalities in
EventDisptcher.
* Add tests for dispatching events to UI/background thread through
nsIAndroidEventDispatcher::dispatch.
* Add tests for dispatching events to UI/background thread through
EventDispatcher.dispatch.
* Add tests for dispatching events to Gecko thread through
EventDispatcher.dispatch.
Each kind of test exercises both the global EventDispatcher through
EventDispatcher.getInstance() and the per-GeckoView EventDispatcher
through GeckoApp.getEventDispatcher().
2016-11-14 13:29:50 +00:00
|
|
|
typedef SupportsWeakPtr<GeckoViewSupport> SupportsWeakPtr;
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(GeckoViewSupport);
|
2015-09-21 14:13:32 +00:00
|
|
|
|
2015-09-21 14:13:33 +00:00
|
|
|
template<typename Functor>
|
2015-10-22 21:45:46 +00:00
|
|
|
static void OnNativeCall(Functor&& aCall)
|
2015-09-21 14:13:33 +00:00
|
|
|
{
|
2015-10-22 21:45:46 +00:00
|
|
|
if (aCall.IsTarget(&Open) && NS_IsMainThread()) {
|
2015-09-21 14:13:33 +00:00
|
|
|
// Gecko state probably just switched to PROFILE_READY, and the
|
|
|
|
// event loop is not running yet. Skip the event loop here so we
|
|
|
|
// can get a head start on opening our window.
|
2015-10-22 21:45:46 +00:00
|
|
|
return aCall();
|
2015-09-21 14:13:33 +00:00
|
|
|
}
|
2016-05-05 15:39:02 +00:00
|
|
|
|
|
|
|
const nsAppShell::Event::Type eventType =
|
|
|
|
aCall.IsTarget(&GeckoViewSupport::OnKeyEvent) ||
|
|
|
|
aCall.IsTarget(&GeckoViewSupport::OnImeReplaceText) ||
|
|
|
|
aCall.IsTarget(&GeckoViewSupport::OnImeUpdateComposition) ?
|
|
|
|
nsAppShell::Event::Type::kUIActivity :
|
|
|
|
nsAppShell::Event::Type::kGeneralActivity;
|
|
|
|
|
|
|
|
nsAppShell::PostEvent(mozilla::MakeUnique<WindowEvent<Functor>>(
|
|
|
|
mozilla::Move(aCall), eventType));
|
2015-09-21 14:13:33 +00:00
|
|
|
}
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
GeckoViewSupport(nsWindow* aWindow,
|
|
|
|
const GeckoView::Window::LocalRef& aInstance,
|
|
|
|
GeckoView::Param aView)
|
2015-10-22 21:45:47 +00:00
|
|
|
: window(*aWindow)
|
2015-12-24 03:03:34 +00:00
|
|
|
, mEditable(GeckoEditable::New(aView))
|
2015-10-22 21:45:47 +00:00
|
|
|
, mIMERanges(new TextRangeArray())
|
|
|
|
, mIMEMaskEventsCount(1) // Mask IME events since there's no focus yet
|
|
|
|
, mIMEUpdatingContext(false)
|
|
|
|
, mIMESelectionChanged(false)
|
2015-12-12 15:18:43 +00:00
|
|
|
, mIMETextChangedDuringFlush(false)
|
2016-07-20 07:19:05 +00:00
|
|
|
, mIMEMonitorCursor(false)
|
2015-12-24 03:03:34 +00:00
|
|
|
{
|
Bug 1307820 - Implement per-GeckoView messaging; r=snorp r=sebastian
Bug 1307820 - 1a. Move GeckoApp EventDispatcher to GeckoView; r=snorp
Make it a GeckoView-specific EventDispatcher instead of
GeckoApp-specific, so that GeckoView consumers can benefit from a
per-view EventDispatcher. In addition, a few events like Gecko:Ready are
moved back to the global EventDispatcher because that makes more sense.
Bug 1307820 - 1b. Don't use GeckoApp EventDispatcher during inflation; r=snorp
During layout inflation, we don't yet have GeckoView and therefore the
GeckoView EventDispatcher, so we should not register events until later,
typically during onAttachedToWindow.
Bug 1307820 - 2. Introduce GeckoBundle; r=snorp
The Android Bundle class has several disadvantages when used for holding
structured data from JS.
The most obvious one is the differentiation between int and double,
which doesn't exist in JS. So when a JS number is converted to either a
Bundle int or double, we run the risk of making a wrong conversion,
resulting in a type mismatch exception when Java uses the Bundle. This
extends to number arrays from JS.
There is one more gotcha when using arrays. When we receive an empty
array from JS, there is no way for us to determine the type of the
array, because even empty arrays in Java have types. We are forced to
pick an arbitrary type like boolean[], which can easily result in a type
mismatch exception when using the array on the Java side.
In addition, Bundle is fairly cumbersome, and we cannot access the inner
structures of Bundle from Java or JNI, making it harder to use.
With these factors in mind, this patch introduces GeckoBundle as a
better choice for Gecko/Java communication. It is almost fully
API-compatible with the Android Bundle; only the Bundle array methods
are different. It resolves the numbers problem by performing conversions
if necessary, and it is a lot more lightweight than Bundle.
Bug 1307820 - 3. Convert BundleEventListener to use GeckoBundle; r=snorp
Convert BundleEventListener from using Bundle to using GeckoBundle.
Because NativeJSContainer still only supports Bundle, we do an extra
conversion when sending Bundle messages, but eventually, as we eliminate
the use of NativeJSContainer, that will go away as well.
Bug 1307820 - 4. Introduce EventDispatcher interfaces; r=snorp
Introduce several new XPCOM interfaces for the new EventDispatcher API,
these interfaces are mostly mirrored after their Java counterparts.
* nsIAndroidEventDispatcher is the main interface for
registering/unregistering listeners and for dispatching events from
JS/C++.
* nsIAndroidEventListener is the interface that JS/C++ clients implement
to receive events.
* nsIAndroidEventCallback is the interface that JS/C++ clients implement
to receive responses from dispatched events.
* nsIAndroidView is the new interface that every window receives
that is specific to the window/GeckoView pair. It is passed to chrome
scripts through window arguments.
Bug 1307820 - 5. Remove EventDispatcher references from gfx code; r=snorp
EventDispatcher was used for JPZC, but NPZC doesn't use it anymore.
Bug 1307820 - 6. General JNI template improvements; r=snorp
This patch includes several improvements to the JNI templates.
* Context::RawClassRef is removed to avoid misuse, as Context::ClassRef
should be used instead.
* Fix a compile error, in certain usages, in the DisposeNative overload
in NativeStub.
* Add Ref::IsInstanceOf and Context::IsInstanceOf to mirror the
JNIEnv::IsInstanceOf call.
* Add Ref::operator* and Context::operator* to provide an easy way to
get a Context object.
* Add built-in declarations for boxed Java objects (e.g. Boolean,
Integer, etc).
* Add ObjectArray::New for creating new object arrays of specific types.
* Add lvalue qualifiers to LocalRef::operator= and GlobalRef::operator=,
to prevent accidentally assigning to rvalues. (e.g.
`objectArray->GetElement(0) = newObject;`, which won't work as intended.)
Bug 1307820 - 7. Support ownership through RefPtr for native JNI objects; r=snorp
In addition to direct ownership and weak pointer ownership, add a third
ownership model where a native JNI object owns a RefPtr that holds a
strong reference to the actual C++ object. This ownership model works
well with ref-counted objects such as XPCOM objects, and is activated
through the presence of public members AddRef() and Release() in the C++
object.
Bug 1307820 - 8. Implement Gecko-side EventDispatcher; r=snorp
Add a skeletal implementation of EventDispatcher on the Gecko side.
Each widget::EventDispatcher will be associated with a Java
EventDispatcher, so events can be dispatched from Gecko to Java and vice
versa. AndroidBridge and nsWindow will implement
nsIAndroidEventDispatcher through widget::EventDispatcher.
Other patches will add more complete functionality such as
GeckoBundle/JSObject translation and support for callbacks.
Bug 1307820 - 9. Implement dispatching between Gecko/Java; r=snorp
Implement translation between JSObject and GeckoBundle, and use that for
dispatching events from Gecko to Java and vice versa.
Bug 1307820 - 10. Implement callback support; r=snorp
Implement callback support for both Gecko-to-Java events and
Java-to-Gecko events.
For Gecko-to-Java, we translate nsIAndroidEventCallback to a Java
EventCallback through NativeCallbackDelegate and pass it to the Java
listener.
For Java-to-Gecko, we translate EventCallback to a
nsIAndroidEventCallback through JavaCallbackDelegate and pass it to the
Gecko listener. There is another JavaCallbackDelegate on the Java side
that redirects the callback to a particular thread. For example, if the
event was dispatched from the UI thread, we make sure the callback
happens on the UI thread as well.
Bug 1307820 - 11. Add BundleEventListener support for Gecko thread; r=snorp
Add support for BundleEventListener on the Gecko thread, so that we can
use it to replace any existing GeckoEventListener or NativeEventListener
implementations that require the listener be run synchronously on the
Gecko thread.
Bug 1307820 - 12. Add global EventDispatcher in AndroidBridge; r=snorp
Add an instance of EventDispatcher to AndroidBridge to act as a global
event dispatcher.
Bug 1307820 - 13. Add per-nsWindow EventDispatcher; r=snorp
Add an instance of EventDispatcher to each nsWindow through an
AndroidView object, which implements nsIAndroidView. The nsIAndroidView
is passed to the chrome script through the window argument when opening
the window.
Bug 1307820 - 14. Update auto-generated bindings; r=me
Bug 1307820 - 15. Update testEventDispatcher; r=snorp
Update testEventDispatcher to include new functionalities in
EventDisptcher.
* Add tests for dispatching events to UI/background thread through
nsIAndroidEventDispatcher::dispatch.
* Add tests for dispatching events to UI/background thread through
EventDispatcher.dispatch.
* Add tests for dispatching events to Gecko thread through
EventDispatcher.dispatch.
Each kind of test exercises both the global EventDispatcher through
EventDispatcher.getInstance() and the per-GeckoView EventDispatcher
through GeckoApp.getEventDispatcher().
2016-11-14 13:29:50 +00:00
|
|
|
Base::AttachNative(aInstance, static_cast<SupportsWeakPtr*>(this));
|
|
|
|
EditableBase::AttachNative(
|
|
|
|
mEditable, static_cast<SupportsWeakPtr*>(this));
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
~GeckoViewSupport();
|
2015-10-22 21:45:47 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
using Base::DisposeNative;
|
|
|
|
using EditableBase::DisposeNative;
|
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
/**
|
|
|
|
* GeckoView methods
|
|
|
|
*/
|
2016-07-21 01:43:34 +00:00
|
|
|
private:
|
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> mDOMWindow;
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
public:
|
2015-09-21 14:13:32 +00:00
|
|
|
// Create and attach a window.
|
2016-02-09 22:27:28 +00:00
|
|
|
static void Open(const jni::Class::LocalRef& aCls,
|
2015-10-22 21:45:46 +00:00
|
|
|
GeckoView::Window::Param aWindow,
|
2016-08-01 18:21:31 +00:00
|
|
|
GeckoView::Param aView, jni::Object::Param aCompositor,
|
Bug 1307820 - Implement per-GeckoView messaging; r=snorp r=sebastian
Bug 1307820 - 1a. Move GeckoApp EventDispatcher to GeckoView; r=snorp
Make it a GeckoView-specific EventDispatcher instead of
GeckoApp-specific, so that GeckoView consumers can benefit from a
per-view EventDispatcher. In addition, a few events like Gecko:Ready are
moved back to the global EventDispatcher because that makes more sense.
Bug 1307820 - 1b. Don't use GeckoApp EventDispatcher during inflation; r=snorp
During layout inflation, we don't yet have GeckoView and therefore the
GeckoView EventDispatcher, so we should not register events until later,
typically during onAttachedToWindow.
Bug 1307820 - 2. Introduce GeckoBundle; r=snorp
The Android Bundle class has several disadvantages when used for holding
structured data from JS.
The most obvious one is the differentiation between int and double,
which doesn't exist in JS. So when a JS number is converted to either a
Bundle int or double, we run the risk of making a wrong conversion,
resulting in a type mismatch exception when Java uses the Bundle. This
extends to number arrays from JS.
There is one more gotcha when using arrays. When we receive an empty
array from JS, there is no way for us to determine the type of the
array, because even empty arrays in Java have types. We are forced to
pick an arbitrary type like boolean[], which can easily result in a type
mismatch exception when using the array on the Java side.
In addition, Bundle is fairly cumbersome, and we cannot access the inner
structures of Bundle from Java or JNI, making it harder to use.
With these factors in mind, this patch introduces GeckoBundle as a
better choice for Gecko/Java communication. It is almost fully
API-compatible with the Android Bundle; only the Bundle array methods
are different. It resolves the numbers problem by performing conversions
if necessary, and it is a lot more lightweight than Bundle.
Bug 1307820 - 3. Convert BundleEventListener to use GeckoBundle; r=snorp
Convert BundleEventListener from using Bundle to using GeckoBundle.
Because NativeJSContainer still only supports Bundle, we do an extra
conversion when sending Bundle messages, but eventually, as we eliminate
the use of NativeJSContainer, that will go away as well.
Bug 1307820 - 4. Introduce EventDispatcher interfaces; r=snorp
Introduce several new XPCOM interfaces for the new EventDispatcher API,
these interfaces are mostly mirrored after their Java counterparts.
* nsIAndroidEventDispatcher is the main interface for
registering/unregistering listeners and for dispatching events from
JS/C++.
* nsIAndroidEventListener is the interface that JS/C++ clients implement
to receive events.
* nsIAndroidEventCallback is the interface that JS/C++ clients implement
to receive responses from dispatched events.
* nsIAndroidView is the new interface that every window receives
that is specific to the window/GeckoView pair. It is passed to chrome
scripts through window arguments.
Bug 1307820 - 5. Remove EventDispatcher references from gfx code; r=snorp
EventDispatcher was used for JPZC, but NPZC doesn't use it anymore.
Bug 1307820 - 6. General JNI template improvements; r=snorp
This patch includes several improvements to the JNI templates.
* Context::RawClassRef is removed to avoid misuse, as Context::ClassRef
should be used instead.
* Fix a compile error, in certain usages, in the DisposeNative overload
in NativeStub.
* Add Ref::IsInstanceOf and Context::IsInstanceOf to mirror the
JNIEnv::IsInstanceOf call.
* Add Ref::operator* and Context::operator* to provide an easy way to
get a Context object.
* Add built-in declarations for boxed Java objects (e.g. Boolean,
Integer, etc).
* Add ObjectArray::New for creating new object arrays of specific types.
* Add lvalue qualifiers to LocalRef::operator= and GlobalRef::operator=,
to prevent accidentally assigning to rvalues. (e.g.
`objectArray->GetElement(0) = newObject;`, which won't work as intended.)
Bug 1307820 - 7. Support ownership through RefPtr for native JNI objects; r=snorp
In addition to direct ownership and weak pointer ownership, add a third
ownership model where a native JNI object owns a RefPtr that holds a
strong reference to the actual C++ object. This ownership model works
well with ref-counted objects such as XPCOM objects, and is activated
through the presence of public members AddRef() and Release() in the C++
object.
Bug 1307820 - 8. Implement Gecko-side EventDispatcher; r=snorp
Add a skeletal implementation of EventDispatcher on the Gecko side.
Each widget::EventDispatcher will be associated with a Java
EventDispatcher, so events can be dispatched from Gecko to Java and vice
versa. AndroidBridge and nsWindow will implement
nsIAndroidEventDispatcher through widget::EventDispatcher.
Other patches will add more complete functionality such as
GeckoBundle/JSObject translation and support for callbacks.
Bug 1307820 - 9. Implement dispatching between Gecko/Java; r=snorp
Implement translation between JSObject and GeckoBundle, and use that for
dispatching events from Gecko to Java and vice versa.
Bug 1307820 - 10. Implement callback support; r=snorp
Implement callback support for both Gecko-to-Java events and
Java-to-Gecko events.
For Gecko-to-Java, we translate nsIAndroidEventCallback to a Java
EventCallback through NativeCallbackDelegate and pass it to the Java
listener.
For Java-to-Gecko, we translate EventCallback to a
nsIAndroidEventCallback through JavaCallbackDelegate and pass it to the
Gecko listener. There is another JavaCallbackDelegate on the Java side
that redirects the callback to a particular thread. For example, if the
event was dispatched from the UI thread, we make sure the callback
happens on the UI thread as well.
Bug 1307820 - 11. Add BundleEventListener support for Gecko thread; r=snorp
Add support for BundleEventListener on the Gecko thread, so that we can
use it to replace any existing GeckoEventListener or NativeEventListener
implementations that require the listener be run synchronously on the
Gecko thread.
Bug 1307820 - 12. Add global EventDispatcher in AndroidBridge; r=snorp
Add an instance of EventDispatcher to AndroidBridge to act as a global
event dispatcher.
Bug 1307820 - 13. Add per-nsWindow EventDispatcher; r=snorp
Add an instance of EventDispatcher to each nsWindow through an
AndroidView object, which implements nsIAndroidView. The nsIAndroidView
is passed to the chrome script through the window argument when opening
the window.
Bug 1307820 - 14. Update auto-generated bindings; r=me
Bug 1307820 - 15. Update testEventDispatcher; r=snorp
Update testEventDispatcher to include new functionalities in
EventDisptcher.
* Add tests for dispatching events to UI/background thread through
nsIAndroidEventDispatcher::dispatch.
* Add tests for dispatching events to UI/background thread through
EventDispatcher.dispatch.
* Add tests for dispatching events to Gecko thread through
EventDispatcher.dispatch.
Each kind of test exercises both the global EventDispatcher through
EventDispatcher.getInstance() and the per-GeckoView EventDispatcher
through GeckoApp.getEventDispatcher().
2016-11-14 13:29:50 +00:00
|
|
|
jni::Object::Param aDispatcher,
|
2016-09-29 06:23:56 +00:00
|
|
|
jni::String::Param aChromeURI,
|
2017-02-16 23:26:20 +00:00
|
|
|
jni::Object::Param aSettings,
|
2016-09-29 06:23:56 +00:00
|
|
|
int32_t screenId);
|
2015-10-08 19:25:49 +00:00
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
// Close and destroy the nsWindow.
|
|
|
|
void Close();
|
|
|
|
|
2015-12-24 03:03:35 +00:00
|
|
|
// Reattach this nsWindow to a new GeckoView.
|
2016-08-18 22:03:04 +00:00
|
|
|
void Reattach(const GeckoView::Window::LocalRef& inst,
|
Bug 1307820 - Implement per-GeckoView messaging; r=snorp r=sebastian
Bug 1307820 - 1a. Move GeckoApp EventDispatcher to GeckoView; r=snorp
Make it a GeckoView-specific EventDispatcher instead of
GeckoApp-specific, so that GeckoView consumers can benefit from a
per-view EventDispatcher. In addition, a few events like Gecko:Ready are
moved back to the global EventDispatcher because that makes more sense.
Bug 1307820 - 1b. Don't use GeckoApp EventDispatcher during inflation; r=snorp
During layout inflation, we don't yet have GeckoView and therefore the
GeckoView EventDispatcher, so we should not register events until later,
typically during onAttachedToWindow.
Bug 1307820 - 2. Introduce GeckoBundle; r=snorp
The Android Bundle class has several disadvantages when used for holding
structured data from JS.
The most obvious one is the differentiation between int and double,
which doesn't exist in JS. So when a JS number is converted to either a
Bundle int or double, we run the risk of making a wrong conversion,
resulting in a type mismatch exception when Java uses the Bundle. This
extends to number arrays from JS.
There is one more gotcha when using arrays. When we receive an empty
array from JS, there is no way for us to determine the type of the
array, because even empty arrays in Java have types. We are forced to
pick an arbitrary type like boolean[], which can easily result in a type
mismatch exception when using the array on the Java side.
In addition, Bundle is fairly cumbersome, and we cannot access the inner
structures of Bundle from Java or JNI, making it harder to use.
With these factors in mind, this patch introduces GeckoBundle as a
better choice for Gecko/Java communication. It is almost fully
API-compatible with the Android Bundle; only the Bundle array methods
are different. It resolves the numbers problem by performing conversions
if necessary, and it is a lot more lightweight than Bundle.
Bug 1307820 - 3. Convert BundleEventListener to use GeckoBundle; r=snorp
Convert BundleEventListener from using Bundle to using GeckoBundle.
Because NativeJSContainer still only supports Bundle, we do an extra
conversion when sending Bundle messages, but eventually, as we eliminate
the use of NativeJSContainer, that will go away as well.
Bug 1307820 - 4. Introduce EventDispatcher interfaces; r=snorp
Introduce several new XPCOM interfaces for the new EventDispatcher API,
these interfaces are mostly mirrored after their Java counterparts.
* nsIAndroidEventDispatcher is the main interface for
registering/unregistering listeners and for dispatching events from
JS/C++.
* nsIAndroidEventListener is the interface that JS/C++ clients implement
to receive events.
* nsIAndroidEventCallback is the interface that JS/C++ clients implement
to receive responses from dispatched events.
* nsIAndroidView is the new interface that every window receives
that is specific to the window/GeckoView pair. It is passed to chrome
scripts through window arguments.
Bug 1307820 - 5. Remove EventDispatcher references from gfx code; r=snorp
EventDispatcher was used for JPZC, but NPZC doesn't use it anymore.
Bug 1307820 - 6. General JNI template improvements; r=snorp
This patch includes several improvements to the JNI templates.
* Context::RawClassRef is removed to avoid misuse, as Context::ClassRef
should be used instead.
* Fix a compile error, in certain usages, in the DisposeNative overload
in NativeStub.
* Add Ref::IsInstanceOf and Context::IsInstanceOf to mirror the
JNIEnv::IsInstanceOf call.
* Add Ref::operator* and Context::operator* to provide an easy way to
get a Context object.
* Add built-in declarations for boxed Java objects (e.g. Boolean,
Integer, etc).
* Add ObjectArray::New for creating new object arrays of specific types.
* Add lvalue qualifiers to LocalRef::operator= and GlobalRef::operator=,
to prevent accidentally assigning to rvalues. (e.g.
`objectArray->GetElement(0) = newObject;`, which won't work as intended.)
Bug 1307820 - 7. Support ownership through RefPtr for native JNI objects; r=snorp
In addition to direct ownership and weak pointer ownership, add a third
ownership model where a native JNI object owns a RefPtr that holds a
strong reference to the actual C++ object. This ownership model works
well with ref-counted objects such as XPCOM objects, and is activated
through the presence of public members AddRef() and Release() in the C++
object.
Bug 1307820 - 8. Implement Gecko-side EventDispatcher; r=snorp
Add a skeletal implementation of EventDispatcher on the Gecko side.
Each widget::EventDispatcher will be associated with a Java
EventDispatcher, so events can be dispatched from Gecko to Java and vice
versa. AndroidBridge and nsWindow will implement
nsIAndroidEventDispatcher through widget::EventDispatcher.
Other patches will add more complete functionality such as
GeckoBundle/JSObject translation and support for callbacks.
Bug 1307820 - 9. Implement dispatching between Gecko/Java; r=snorp
Implement translation between JSObject and GeckoBundle, and use that for
dispatching events from Gecko to Java and vice versa.
Bug 1307820 - 10. Implement callback support; r=snorp
Implement callback support for both Gecko-to-Java events and
Java-to-Gecko events.
For Gecko-to-Java, we translate nsIAndroidEventCallback to a Java
EventCallback through NativeCallbackDelegate and pass it to the Java
listener.
For Java-to-Gecko, we translate EventCallback to a
nsIAndroidEventCallback through JavaCallbackDelegate and pass it to the
Gecko listener. There is another JavaCallbackDelegate on the Java side
that redirects the callback to a particular thread. For example, if the
event was dispatched from the UI thread, we make sure the callback
happens on the UI thread as well.
Bug 1307820 - 11. Add BundleEventListener support for Gecko thread; r=snorp
Add support for BundleEventListener on the Gecko thread, so that we can
use it to replace any existing GeckoEventListener or NativeEventListener
implementations that require the listener be run synchronously on the
Gecko thread.
Bug 1307820 - 12. Add global EventDispatcher in AndroidBridge; r=snorp
Add an instance of EventDispatcher to AndroidBridge to act as a global
event dispatcher.
Bug 1307820 - 13. Add per-nsWindow EventDispatcher; r=snorp
Add an instance of EventDispatcher to each nsWindow through an
AndroidView object, which implements nsIAndroidView. The nsIAndroidView
is passed to the chrome script through the window argument when opening
the window.
Bug 1307820 - 14. Update auto-generated bindings; r=me
Bug 1307820 - 15. Update testEventDispatcher; r=snorp
Update testEventDispatcher to include new functionalities in
EventDisptcher.
* Add tests for dispatching events to UI/background thread through
nsIAndroidEventDispatcher::dispatch.
* Add tests for dispatching events to UI/background thread through
EventDispatcher.dispatch.
* Add tests for dispatching events to Gecko thread through
EventDispatcher.dispatch.
Each kind of test exercises both the global EventDispatcher through
EventDispatcher.getInstance() and the per-GeckoView EventDispatcher
through GeckoApp.getEventDispatcher().
2016-11-14 13:29:50 +00:00
|
|
|
GeckoView::Param aView, jni::Object::Param aCompositor,
|
|
|
|
jni::Object::Param aDispatcher);
|
2015-12-24 03:03:35 +00:00
|
|
|
|
2016-07-21 01:43:34 +00:00
|
|
|
void LoadUri(jni::String::Param aUri, int32_t aFlags);
|
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
/**
|
|
|
|
* GeckoEditable methods
|
|
|
|
*/
|
2015-10-22 21:45:47 +00:00
|
|
|
private:
|
|
|
|
/*
|
|
|
|
Rules for managing IME between Gecko and Java:
|
|
|
|
|
|
|
|
* Gecko controls the text content, and Java shadows the Gecko text
|
|
|
|
through text updates
|
2015-11-03 16:53:57 +00:00
|
|
|
* Gecko and Java maintain separate selections, and synchronize when
|
|
|
|
needed through selection updates and set-selection events
|
2015-10-22 21:45:47 +00:00
|
|
|
* Java controls the composition, and Gecko shadows the Java
|
|
|
|
composition through update composition events
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct IMETextChange final {
|
|
|
|
int32_t mStart, mOldEnd, mNewEnd;
|
|
|
|
|
|
|
|
IMETextChange() :
|
|
|
|
mStart(-1), mOldEnd(-1), mNewEnd(-1) {}
|
|
|
|
|
|
|
|
IMETextChange(const IMENotification& aIMENotification)
|
|
|
|
: mStart(aIMENotification.mTextChangeData.mStartOffset)
|
|
|
|
, mOldEnd(aIMENotification.mTextChangeData.mRemovedEndOffset)
|
|
|
|
, mNewEnd(aIMENotification.mTextChangeData.mAddedEndOffset)
|
|
|
|
{
|
2016-07-21 17:49:04 +00:00
|
|
|
MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE,
|
2015-10-22 21:45:47 +00:00
|
|
|
"IMETextChange initialized with wrong notification");
|
|
|
|
MOZ_ASSERT(aIMENotification.mTextChangeData.IsValid(),
|
|
|
|
"The text change notification isn't initialized");
|
|
|
|
MOZ_ASSERT(aIMENotification.mTextChangeData.IsInInt32Range(),
|
|
|
|
"The text change notification is out of range");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsEmpty() const { return mStart < 0; }
|
|
|
|
};
|
|
|
|
|
|
|
|
// GeckoEditable instance used by this nsWindow;
|
2016-07-21 17:49:04 +00:00
|
|
|
java::GeckoEditable::GlobalRef mEditable;
|
2016-02-02 15:36:30 +00:00
|
|
|
AutoTArray<mozilla::UniquePtr<mozilla::WidgetEvent>, 8> mIMEKeyEvents;
|
|
|
|
AutoTArray<IMETextChange, 4> mIMETextChanges;
|
2015-10-22 21:45:47 +00:00
|
|
|
InputContext mInputContext;
|
|
|
|
RefPtr<mozilla::TextRangeArray> mIMERanges;
|
2016-10-25 16:28:53 +00:00
|
|
|
int32_t mIMEMaskEventsCount; // Mask events when > 0.
|
2015-10-22 21:45:47 +00:00
|
|
|
bool mIMEUpdatingContext;
|
|
|
|
bool mIMESelectionChanged;
|
2015-12-12 15:18:43 +00:00
|
|
|
bool mIMETextChangedDuringFlush;
|
2016-07-20 07:19:05 +00:00
|
|
|
bool mIMEMonitorCursor;
|
2015-10-22 21:45:47 +00:00
|
|
|
|
|
|
|
void SendIMEDummyKeyEvents();
|
|
|
|
void AddIMETextChange(const IMETextChange& aChange);
|
2015-12-12 15:18:43 +00:00
|
|
|
|
|
|
|
enum FlushChangesFlag {
|
2017-01-13 19:39:27 +00:00
|
|
|
// Not retrying.
|
2015-12-12 15:18:43 +00:00
|
|
|
FLUSH_FLAG_NONE,
|
2017-01-13 19:39:27 +00:00
|
|
|
// Retrying due to IME text changes during flush.
|
|
|
|
FLUSH_FLAG_RETRY,
|
|
|
|
// Retrying due to IME sync exceptions during flush.
|
|
|
|
FLUSH_FLAG_RECOVER
|
2015-12-12 15:18:43 +00:00
|
|
|
};
|
2016-01-07 02:33:18 +00:00
|
|
|
void PostFlushIMEChanges();
|
2015-12-12 15:18:43 +00:00
|
|
|
void FlushIMEChanges(FlushChangesFlag aFlags = FLUSH_FLAG_NONE);
|
2017-01-13 19:39:27 +00:00
|
|
|
void FlushIMEText(FlushChangesFlag aFlags = FLUSH_FLAG_NONE);
|
2016-02-26 19:38:57 +00:00
|
|
|
void AsyncNotifyIME(int32_t aNotification);
|
2016-07-20 07:19:05 +00:00
|
|
|
void UpdateCompositionRects();
|
2015-10-22 21:45:47 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
bool NotifyIME(const IMENotification& aIMENotification);
|
|
|
|
void SetInputContext(const InputContext& aContext,
|
|
|
|
const InputContextAction& aAction);
|
|
|
|
InputContext GetInputContext();
|
|
|
|
|
2016-02-10 04:36:41 +00:00
|
|
|
// RAII helper class that automatically sends an event reply through
|
|
|
|
// OnImeSynchronize, as required by events like OnImeReplaceText.
|
|
|
|
class AutoIMESynchronize {
|
|
|
|
GeckoViewSupport* const mGVS;
|
|
|
|
public:
|
|
|
|
AutoIMESynchronize(GeckoViewSupport* gvs) : mGVS(gvs) {}
|
|
|
|
~AutoIMESynchronize() { mGVS->OnImeSynchronize(); }
|
|
|
|
};
|
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
// Handle an Android KeyEvent.
|
2015-10-22 21:45:46 +00:00
|
|
|
void OnKeyEvent(int32_t aAction, int32_t aKeyCode, int32_t aScanCode,
|
|
|
|
int32_t aMetaState, int64_t aTime, int32_t aUnicodeChar,
|
|
|
|
int32_t aBaseUnicodeChar, int32_t aDomPrintableKeyValue,
|
|
|
|
int32_t aRepeatCount, int32_t aFlags,
|
2016-03-01 12:49:54 +00:00
|
|
|
bool aIsSynthesizedImeKey, jni::Object::Param originalEvent);
|
2015-10-22 21:45:46 +00:00
|
|
|
|
|
|
|
// Synchronize Gecko thread with the InputConnection thread.
|
|
|
|
void OnImeSynchronize();
|
|
|
|
|
|
|
|
// Replace a range of text with new text.
|
2015-10-22 21:45:47 +00:00
|
|
|
void OnImeReplaceText(int32_t aStart, int32_t aEnd,
|
2015-11-03 16:53:58 +00:00
|
|
|
jni::String::Param aText);
|
2015-10-22 21:45:46 +00:00
|
|
|
|
|
|
|
// Add styling for a range within the active composition.
|
2015-10-22 21:45:47 +00:00
|
|
|
void OnImeAddCompositionRange(int32_t aStart, int32_t aEnd,
|
|
|
|
int32_t aRangeType, int32_t aRangeStyle, int32_t aRangeLineStyle,
|
|
|
|
bool aRangeBoldLine, int32_t aRangeForeColor,
|
|
|
|
int32_t aRangeBackColor, int32_t aRangeLineColor);
|
2015-10-22 21:45:46 +00:00
|
|
|
|
|
|
|
// Update styling for the active composition using previous-added ranges.
|
2015-10-22 21:45:47 +00:00
|
|
|
void OnImeUpdateComposition(int32_t aStart, int32_t aEnd);
|
2016-07-20 07:19:05 +00:00
|
|
|
|
|
|
|
// Set cursor mode whether IME requests
|
|
|
|
void OnImeRequestCursorUpdates(int aRequestMode);
|
2015-09-21 14:13:32 +00:00
|
|
|
};
|
|
|
|
|
2016-01-15 18:05:45 +00:00
|
|
|
/**
|
|
|
|
* NativePanZoomController handles its native calls on the UI thread, so make
|
|
|
|
* it separate from GeckoViewSupport.
|
|
|
|
*/
|
|
|
|
class nsWindow::NPZCSupport final
|
|
|
|
: public NativePanZoomController::Natives<NPZCSupport>
|
|
|
|
{
|
2016-08-18 22:03:04 +00:00
|
|
|
using LockedWindowPtr = WindowPtr<NPZCSupport>::Locked;
|
|
|
|
|
|
|
|
WindowPtr<NPZCSupport> mWindow;
|
2016-01-15 18:05:45 +00:00
|
|
|
NativePanZoomController::GlobalRef mNPZC;
|
2016-03-11 23:29:50 +00:00
|
|
|
int mPreviousButtons;
|
2016-01-15 18:05:45 +00:00
|
|
|
|
2016-12-21 18:37:20 +00:00
|
|
|
template<typename Lambda>
|
|
|
|
class InputEvent final : public nsAppShell::Event
|
|
|
|
{
|
|
|
|
NativePanZoomController::GlobalRef mNPZC;
|
|
|
|
Lambda mLambda;
|
|
|
|
|
|
|
|
public:
|
|
|
|
InputEvent(const NPZCSupport* aNPZCSupport, Lambda&& aLambda)
|
|
|
|
: mNPZC(aNPZCSupport->mNPZC)
|
|
|
|
, mLambda(mozilla::Move(aLambda))
|
|
|
|
{}
|
|
|
|
|
|
|
|
void Run() override
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
JNIEnv* const env = jni::GetGeckoThreadEnv();
|
|
|
|
NPZCSupport* npzcSupport = GetNative(
|
|
|
|
NativePanZoomController::LocalRef(env, mNPZC));
|
|
|
|
|
|
|
|
if (!npzcSupport || !npzcSupport->mWindow) {
|
|
|
|
// We already shut down.
|
|
|
|
env->ExceptionClear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsWindow* const window = npzcSupport->mWindow;
|
|
|
|
window->UserActivity();
|
|
|
|
return mLambda(window);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAppShell::Event::Type ActivityType() const override
|
|
|
|
{
|
|
|
|
return nsAppShell::Event::Type::kUIActivity;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename Lambda>
|
|
|
|
void PostInputEvent(Lambda&& aLambda)
|
|
|
|
{
|
|
|
|
nsAppShell::PostEvent(MakeUnique<InputEvent<Lambda>>(
|
|
|
|
this, mozilla::Move(aLambda)));
|
|
|
|
}
|
|
|
|
|
2016-01-15 18:05:45 +00:00
|
|
|
public:
|
|
|
|
typedef NativePanZoomController::Natives<NPZCSupport> Base;
|
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
NPZCSupport(NativePtr<NPZCSupport>* aPtr, nsWindow* aWindow,
|
2016-01-15 18:05:45 +00:00
|
|
|
const NativePanZoomController::LocalRef& aNPZC)
|
2016-08-18 22:03:04 +00:00
|
|
|
: mWindow(aPtr, aWindow)
|
2016-01-15 18:05:45 +00:00
|
|
|
, mNPZC(aNPZC)
|
2016-03-11 23:29:50 +00:00
|
|
|
, mPreviousButtons(0)
|
2016-08-18 22:03:04 +00:00
|
|
|
{}
|
2016-01-15 18:05:45 +00:00
|
|
|
|
|
|
|
~NPZCSupport()
|
|
|
|
{}
|
|
|
|
|
|
|
|
using Base::AttachNative;
|
2016-08-18 22:03:04 +00:00
|
|
|
using Base::DisposeNative;
|
2016-01-15 18:05:45 +00:00
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
void OnDetach()
|
2016-01-15 18:05:45 +00:00
|
|
|
{
|
|
|
|
// 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.
|
|
|
|
//
|
2016-08-18 22:03:04 +00:00
|
|
|
// 1) happens through OnDetach, which first notifies the UI
|
2016-01-15 18:05:45 +00:00
|
|
|
// 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.
|
|
|
|
//
|
2016-08-18 22:03:04 +00:00
|
|
|
// 4) happens through DisposeNative directly. OnDetach is not
|
2016-01-15 18:05:45 +00:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2016-01-28 21:00:05 +00:00
|
|
|
void AdjustScrollForSurfaceShift(float aX, float aY)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
|
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
RefPtr<IAPZCTreeManager> controller;
|
|
|
|
|
|
|
|
if (LockedWindowPtr window{mWindow}) {
|
|
|
|
controller = window->mAPZC;
|
2016-01-28 21:00:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (controller) {
|
|
|
|
controller->AdjustScrollForSurfaceShift(
|
|
|
|
ScreenPoint(aX, aY));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-15 18:05:45 +00:00
|
|
|
void SetIsLongpressEnabled(bool aIsLongpressEnabled)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
|
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
RefPtr<IAPZCTreeManager> controller;
|
|
|
|
|
|
|
|
if (LockedWindowPtr window{mWindow}) {
|
|
|
|
controller = window->mAPZC;
|
|
|
|
}
|
|
|
|
|
2016-07-20 11:37:00 +00:00
|
|
|
if (controller) {
|
|
|
|
controller->SetLongTapEnabled(aIsLongpressEnabled);
|
|
|
|
}
|
2016-01-15 18:05:45 +00:00
|
|
|
}
|
|
|
|
|
2016-02-12 00:34:58 +00:00
|
|
|
bool HandleScrollEvent(int64_t aTime, int32_t aMetaState,
|
|
|
|
float aX, float aY,
|
|
|
|
float aHScroll, float aVScroll)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
|
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
RefPtr<IAPZCTreeManager> controller;
|
|
|
|
|
|
|
|
if (LockedWindowPtr window{mWindow}) {
|
|
|
|
controller = window->mAPZC;
|
2016-02-12 00:34:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!controller) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-02-18 00:19:34 +00:00
|
|
|
ScreenPoint origin = ScreenPoint(aX, aY);
|
2016-02-12 00:34:58 +00:00
|
|
|
|
2016-12-27 01:59:15 +00:00
|
|
|
ScrollWheelInput input(aTime, GetEventTimeStamp(aTime), GetModifiers(aMetaState),
|
2016-02-12 00:34:58 +00:00
|
|
|
ScrollWheelInput::SCROLLMODE_SMOOTH,
|
|
|
|
ScrollWheelInput::SCROLLDELTA_PIXEL,
|
|
|
|
origin,
|
|
|
|
aHScroll, aVScroll,
|
|
|
|
false);
|
|
|
|
|
|
|
|
ScrollableLayerGuid guid;
|
|
|
|
uint64_t blockId;
|
|
|
|
nsEventStatus status = controller->ReceiveInputEvent(input, &guid, &blockId);
|
|
|
|
|
|
|
|
if (status == nsEventStatus_eConsumeNoDefault) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-21 18:37:20 +00:00
|
|
|
PostInputEvent([input, guid, blockId, status] (nsWindow* window) {
|
2016-02-12 00:34:58 +00:00
|
|
|
WidgetWheelEvent wheelEvent = input.ToWidgetWheelEvent(window);
|
|
|
|
window->ProcessUntransformedAPZEvent(&wheelEvent, guid,
|
|
|
|
blockId, status);
|
|
|
|
});
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
private:
|
2016-03-11 23:29:50 +00:00
|
|
|
static MouseInput::ButtonType GetButtonType(int button)
|
|
|
|
{
|
|
|
|
MouseInput::ButtonType result = MouseInput::NONE;
|
|
|
|
|
|
|
|
switch (button) {
|
2016-07-21 17:49:04 +00:00
|
|
|
case java::sdk::MotionEvent::BUTTON_PRIMARY:
|
2016-03-11 23:29:50 +00:00
|
|
|
result = MouseInput::LEFT_BUTTON;
|
|
|
|
break;
|
2016-07-21 17:49:04 +00:00
|
|
|
case java::sdk::MotionEvent::BUTTON_SECONDARY:
|
2016-03-11 23:29:50 +00:00
|
|
|
result = MouseInput::RIGHT_BUTTON;
|
|
|
|
break;
|
2016-07-21 17:49:04 +00:00
|
|
|
case java::sdk::MotionEvent::BUTTON_TERTIARY:
|
2016-03-11 23:29:50 +00:00
|
|
|
result = MouseInput::MIDDLE_BUTTON;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int16_t ConvertButtons(int buttons) {
|
|
|
|
int16_t result = 0;
|
|
|
|
|
2016-07-21 17:49:04 +00:00
|
|
|
if (buttons & java::sdk::MotionEvent::BUTTON_PRIMARY) {
|
2016-03-11 23:29:50 +00:00
|
|
|
result |= WidgetMouseEventBase::eLeftButtonFlag;
|
|
|
|
}
|
2016-07-21 17:49:04 +00:00
|
|
|
if (buttons & java::sdk::MotionEvent::BUTTON_SECONDARY) {
|
2016-03-11 23:29:50 +00:00
|
|
|
result |= WidgetMouseEventBase::eRightButtonFlag;
|
|
|
|
}
|
2016-07-21 17:49:04 +00:00
|
|
|
if (buttons & java::sdk::MotionEvent::BUTTON_TERTIARY) {
|
2016-03-11 23:29:50 +00:00
|
|
|
result |= WidgetMouseEventBase::eMiddleButtonFlag;
|
|
|
|
}
|
2016-07-21 17:49:04 +00:00
|
|
|
if (buttons & java::sdk::MotionEvent::BUTTON_BACK) {
|
2016-03-11 23:29:50 +00:00
|
|
|
result |= WidgetMouseEventBase::e4thButtonFlag;
|
|
|
|
}
|
2016-07-21 17:49:04 +00:00
|
|
|
if (buttons & java::sdk::MotionEvent::BUTTON_FORWARD) {
|
2016-03-11 23:29:50 +00:00
|
|
|
result |= WidgetMouseEventBase::e5thButtonFlag;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
public:
|
2016-03-11 23:29:50 +00:00
|
|
|
bool HandleMouseEvent(int32_t aAction, int64_t aTime, int32_t aMetaState,
|
|
|
|
float aX, float aY, int buttons)
|
2016-02-17 21:57:12 +00:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
|
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
RefPtr<IAPZCTreeManager> controller;
|
|
|
|
|
|
|
|
if (LockedWindowPtr window{mWindow}) {
|
|
|
|
controller = window->mAPZC;
|
2016-02-17 21:57:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!controller) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-03-11 23:29:50 +00:00
|
|
|
MouseInput::MouseType mouseType = MouseInput::MOUSE_NONE;
|
|
|
|
MouseInput::ButtonType buttonType = MouseInput::NONE;
|
2016-02-17 21:57:12 +00:00
|
|
|
switch (aAction) {
|
2016-03-11 23:29:50 +00:00
|
|
|
case AndroidMotionEvent::ACTION_DOWN:
|
|
|
|
mouseType = MouseInput::MOUSE_DOWN;
|
|
|
|
buttonType = GetButtonType(buttons ^ mPreviousButtons);
|
|
|
|
mPreviousButtons = buttons;
|
|
|
|
break;
|
|
|
|
case AndroidMotionEvent::ACTION_UP:
|
|
|
|
mouseType = MouseInput::MOUSE_UP;
|
|
|
|
buttonType = GetButtonType(buttons ^ mPreviousButtons);
|
|
|
|
mPreviousButtons = buttons;
|
|
|
|
break;
|
|
|
|
case AndroidMotionEvent::ACTION_MOVE:
|
|
|
|
mouseType = MouseInput::MOUSE_MOVE;
|
|
|
|
break;
|
2016-02-17 21:57:12 +00:00
|
|
|
case AndroidMotionEvent::ACTION_HOVER_MOVE:
|
2016-03-11 23:29:50 +00:00
|
|
|
mouseType = MouseInput::MOUSE_MOVE;
|
2016-02-17 21:57:12 +00:00
|
|
|
break;
|
|
|
|
case AndroidMotionEvent::ACTION_HOVER_ENTER:
|
2016-03-11 23:29:50 +00:00
|
|
|
mouseType = MouseInput::MOUSE_WIDGET_ENTER;
|
2016-02-17 21:57:12 +00:00
|
|
|
break;
|
|
|
|
case AndroidMotionEvent::ACTION_HOVER_EXIT:
|
2016-03-11 23:29:50 +00:00
|
|
|
mouseType = MouseInput::MOUSE_WIDGET_EXIT;
|
2016-02-17 21:57:12 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-03-11 23:29:50 +00:00
|
|
|
if (mouseType == MouseInput::MOUSE_NONE) {
|
2016-02-17 21:57:12 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-02-18 00:19:34 +00:00
|
|
|
ScreenPoint origin = ScreenPoint(aX, aY);
|
2016-02-17 21:57:12 +00:00
|
|
|
|
2016-12-27 01:59:15 +00:00
|
|
|
MouseInput input(mouseType, buttonType, nsIDOMMouseEvent::MOZ_SOURCE_MOUSE, ConvertButtons(buttons), origin, aTime, GetEventTimeStamp(aTime), GetModifiers(aMetaState));
|
2016-02-17 21:57:12 +00:00
|
|
|
|
|
|
|
ScrollableLayerGuid guid;
|
|
|
|
uint64_t blockId;
|
|
|
|
nsEventStatus status = controller->ReceiveInputEvent(input, &guid, &blockId);
|
|
|
|
|
|
|
|
if (status == nsEventStatus_eConsumeNoDefault) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-21 18:37:20 +00:00
|
|
|
PostInputEvent([input, guid, blockId, status] (nsWindow* window) {
|
2016-02-17 21:57:12 +00:00
|
|
|
WidgetMouseEvent mouseEvent = input.ToWidgetMouseEvent(window);
|
|
|
|
window->ProcessUntransformedAPZEvent(&mouseEvent, guid,
|
|
|
|
blockId, status);
|
|
|
|
});
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-01-15 18:05:45 +00:00
|
|
|
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());
|
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
RefPtr<IAPZCTreeManager> controller;
|
|
|
|
|
|
|
|
if (LockedWindowPtr window{mWindow}) {
|
|
|
|
controller = window->mAPZC;
|
2016-01-15 18:05:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!controller) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-02-09 22:27:28 +00:00
|
|
|
nsTArray<int32_t> pointerId(aPointerId->GetElements());
|
2016-01-15 18:05:45 +00:00
|
|
|
MultiTouchInput::MultiTouchType type;
|
|
|
|
size_t startIndex = 0;
|
|
|
|
size_t endIndex = pointerId.Length();
|
|
|
|
|
|
|
|
switch (aAction) {
|
2016-01-15 18:05:45 +00:00
|
|
|
case sdk::MotionEvent::ACTION_DOWN:
|
|
|
|
case sdk::MotionEvent::ACTION_POINTER_DOWN:
|
2016-01-15 18:05:45 +00:00
|
|
|
type = MultiTouchInput::MULTITOUCH_START;
|
|
|
|
break;
|
2016-01-15 18:05:45 +00:00
|
|
|
case sdk::MotionEvent::ACTION_MOVE:
|
2016-01-15 18:05:45 +00:00
|
|
|
type = MultiTouchInput::MULTITOUCH_MOVE;
|
|
|
|
break;
|
2016-01-15 18:05:45 +00:00
|
|
|
case sdk::MotionEvent::ACTION_UP:
|
|
|
|
case sdk::MotionEvent::ACTION_POINTER_UP:
|
2016-01-15 18:05:45 +00:00
|
|
|
// 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;
|
2016-01-15 18:05:45 +00:00
|
|
|
case sdk::MotionEvent::ACTION_OUTSIDE:
|
|
|
|
case sdk::MotionEvent::ACTION_CANCEL:
|
2016-01-15 18:05:45 +00:00
|
|
|
type = MultiTouchInput::MULTITOUCH_CANCEL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-12-27 01:59:15 +00:00
|
|
|
MultiTouchInput input(type, aTime, GetEventTimeStamp(aTime), 0);
|
2016-01-15 18:05:45 +00:00
|
|
|
input.modifiers = GetModifiers(aMetaState);
|
|
|
|
input.mTouches.SetCapacity(endIndex - startIndex);
|
|
|
|
|
2016-02-09 22:27:28 +00:00
|
|
|
nsTArray<float> x(aX->GetElements());
|
|
|
|
nsTArray<float> y(aY->GetElements());
|
|
|
|
nsTArray<float> orientation(aOrientation->GetElements());
|
|
|
|
nsTArray<float> pressure(aPressure->GetElements());
|
|
|
|
nsTArray<float> toolMajor(aToolMajor->GetElements());
|
|
|
|
nsTArray<float> toolMinor(aToolMinor->GetElements());
|
2016-01-15 18:05:45 +00:00
|
|
|
|
|
|
|
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());
|
|
|
|
|
|
|
|
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])),
|
2016-02-18 00:19:34 +00:00
|
|
|
int32_t(floorf(y[i])));
|
2016-01-15 18:05:45 +00:00
|
|
|
|
|
|
|
// 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.
|
2016-12-21 18:37:20 +00:00
|
|
|
PostInputEvent([input, guid, blockId, status] (nsWindow* window) {
|
2016-01-15 18:05:45 +00:00
|
|
|
WidgetTouchEvent touchEvent = input.ToWidgetTouchEvent(window);
|
|
|
|
window->ProcessUntransformedAPZEvent(&touchEvent, guid,
|
|
|
|
blockId, status);
|
|
|
|
window->DispatchHitTest(touchEvent);
|
|
|
|
});
|
|
|
|
return true;
|
|
|
|
}
|
2016-01-26 01:30:55 +00:00
|
|
|
|
2016-04-05 22:12:48 +00:00
|
|
|
void HandleMotionEventVelocity(int64_t aTime, float aSpeedY)
|
|
|
|
{
|
2016-08-18 22:03:04 +00:00
|
|
|
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
|
|
|
|
|
|
|
|
RefPtr<IAPZCTreeManager> controller;
|
|
|
|
|
|
|
|
if (LockedWindowPtr window{mWindow}) {
|
|
|
|
controller = window->mAPZC;
|
|
|
|
}
|
|
|
|
|
2016-04-05 22:12:48 +00:00
|
|
|
if (controller) {
|
|
|
|
controller->ProcessTouchVelocity((uint32_t)aTime, aSpeedY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-26 01:30:55 +00:00
|
|
|
void UpdateOverscrollVelocity(const float x, const float y)
|
|
|
|
{
|
|
|
|
mNPZC->UpdateOverscrollVelocity(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateOverscrollOffset(const float x, const float y)
|
|
|
|
{
|
|
|
|
mNPZC->UpdateOverscrollOffset(x, y);
|
|
|
|
}
|
2016-03-10 23:06:13 +00:00
|
|
|
|
2016-03-24 22:00:27 +00:00
|
|
|
void SetScrollingRootContent(const bool isRootContent)
|
|
|
|
{
|
|
|
|
mNPZC->SetScrollingRootContent(isRootContent);
|
|
|
|
}
|
|
|
|
|
2016-03-10 23:06:13 +00:00
|
|
|
void SetSelectionDragState(const bool aState)
|
|
|
|
{
|
|
|
|
mNPZC->OnSelectionDragState(aState);
|
|
|
|
}
|
2016-01-15 18:05:45 +00:00
|
|
|
};
|
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
template<> const char
|
|
|
|
nsWindow::NativePtr<nsWindow::NPZCSupport>::sName[] = "NPZCSupport";
|
|
|
|
|
Bug 1307820 - Implement per-GeckoView messaging; r=snorp r=sebastian
Bug 1307820 - 1a. Move GeckoApp EventDispatcher to GeckoView; r=snorp
Make it a GeckoView-specific EventDispatcher instead of
GeckoApp-specific, so that GeckoView consumers can benefit from a
per-view EventDispatcher. In addition, a few events like Gecko:Ready are
moved back to the global EventDispatcher because that makes more sense.
Bug 1307820 - 1b. Don't use GeckoApp EventDispatcher during inflation; r=snorp
During layout inflation, we don't yet have GeckoView and therefore the
GeckoView EventDispatcher, so we should not register events until later,
typically during onAttachedToWindow.
Bug 1307820 - 2. Introduce GeckoBundle; r=snorp
The Android Bundle class has several disadvantages when used for holding
structured data from JS.
The most obvious one is the differentiation between int and double,
which doesn't exist in JS. So when a JS number is converted to either a
Bundle int or double, we run the risk of making a wrong conversion,
resulting in a type mismatch exception when Java uses the Bundle. This
extends to number arrays from JS.
There is one more gotcha when using arrays. When we receive an empty
array from JS, there is no way for us to determine the type of the
array, because even empty arrays in Java have types. We are forced to
pick an arbitrary type like boolean[], which can easily result in a type
mismatch exception when using the array on the Java side.
In addition, Bundle is fairly cumbersome, and we cannot access the inner
structures of Bundle from Java or JNI, making it harder to use.
With these factors in mind, this patch introduces GeckoBundle as a
better choice for Gecko/Java communication. It is almost fully
API-compatible with the Android Bundle; only the Bundle array methods
are different. It resolves the numbers problem by performing conversions
if necessary, and it is a lot more lightweight than Bundle.
Bug 1307820 - 3. Convert BundleEventListener to use GeckoBundle; r=snorp
Convert BundleEventListener from using Bundle to using GeckoBundle.
Because NativeJSContainer still only supports Bundle, we do an extra
conversion when sending Bundle messages, but eventually, as we eliminate
the use of NativeJSContainer, that will go away as well.
Bug 1307820 - 4. Introduce EventDispatcher interfaces; r=snorp
Introduce several new XPCOM interfaces for the new EventDispatcher API,
these interfaces are mostly mirrored after their Java counterparts.
* nsIAndroidEventDispatcher is the main interface for
registering/unregistering listeners and for dispatching events from
JS/C++.
* nsIAndroidEventListener is the interface that JS/C++ clients implement
to receive events.
* nsIAndroidEventCallback is the interface that JS/C++ clients implement
to receive responses from dispatched events.
* nsIAndroidView is the new interface that every window receives
that is specific to the window/GeckoView pair. It is passed to chrome
scripts through window arguments.
Bug 1307820 - 5. Remove EventDispatcher references from gfx code; r=snorp
EventDispatcher was used for JPZC, but NPZC doesn't use it anymore.
Bug 1307820 - 6. General JNI template improvements; r=snorp
This patch includes several improvements to the JNI templates.
* Context::RawClassRef is removed to avoid misuse, as Context::ClassRef
should be used instead.
* Fix a compile error, in certain usages, in the DisposeNative overload
in NativeStub.
* Add Ref::IsInstanceOf and Context::IsInstanceOf to mirror the
JNIEnv::IsInstanceOf call.
* Add Ref::operator* and Context::operator* to provide an easy way to
get a Context object.
* Add built-in declarations for boxed Java objects (e.g. Boolean,
Integer, etc).
* Add ObjectArray::New for creating new object arrays of specific types.
* Add lvalue qualifiers to LocalRef::operator= and GlobalRef::operator=,
to prevent accidentally assigning to rvalues. (e.g.
`objectArray->GetElement(0) = newObject;`, which won't work as intended.)
Bug 1307820 - 7. Support ownership through RefPtr for native JNI objects; r=snorp
In addition to direct ownership and weak pointer ownership, add a third
ownership model where a native JNI object owns a RefPtr that holds a
strong reference to the actual C++ object. This ownership model works
well with ref-counted objects such as XPCOM objects, and is activated
through the presence of public members AddRef() and Release() in the C++
object.
Bug 1307820 - 8. Implement Gecko-side EventDispatcher; r=snorp
Add a skeletal implementation of EventDispatcher on the Gecko side.
Each widget::EventDispatcher will be associated with a Java
EventDispatcher, so events can be dispatched from Gecko to Java and vice
versa. AndroidBridge and nsWindow will implement
nsIAndroidEventDispatcher through widget::EventDispatcher.
Other patches will add more complete functionality such as
GeckoBundle/JSObject translation and support for callbacks.
Bug 1307820 - 9. Implement dispatching between Gecko/Java; r=snorp
Implement translation between JSObject and GeckoBundle, and use that for
dispatching events from Gecko to Java and vice versa.
Bug 1307820 - 10. Implement callback support; r=snorp
Implement callback support for both Gecko-to-Java events and
Java-to-Gecko events.
For Gecko-to-Java, we translate nsIAndroidEventCallback to a Java
EventCallback through NativeCallbackDelegate and pass it to the Java
listener.
For Java-to-Gecko, we translate EventCallback to a
nsIAndroidEventCallback through JavaCallbackDelegate and pass it to the
Gecko listener. There is another JavaCallbackDelegate on the Java side
that redirects the callback to a particular thread. For example, if the
event was dispatched from the UI thread, we make sure the callback
happens on the UI thread as well.
Bug 1307820 - 11. Add BundleEventListener support for Gecko thread; r=snorp
Add support for BundleEventListener on the Gecko thread, so that we can
use it to replace any existing GeckoEventListener or NativeEventListener
implementations that require the listener be run synchronously on the
Gecko thread.
Bug 1307820 - 12. Add global EventDispatcher in AndroidBridge; r=snorp
Add an instance of EventDispatcher to AndroidBridge to act as a global
event dispatcher.
Bug 1307820 - 13. Add per-nsWindow EventDispatcher; r=snorp
Add an instance of EventDispatcher to each nsWindow through an
AndroidView object, which implements nsIAndroidView. The nsIAndroidView
is passed to the chrome script through the window argument when opening
the window.
Bug 1307820 - 14. Update auto-generated bindings; r=me
Bug 1307820 - 15. Update testEventDispatcher; r=snorp
Update testEventDispatcher to include new functionalities in
EventDisptcher.
* Add tests for dispatching events to UI/background thread through
nsIAndroidEventDispatcher::dispatch.
* Add tests for dispatching events to UI/background thread through
EventDispatcher.dispatch.
* Add tests for dispatching events to Gecko thread through
EventDispatcher.dispatch.
Each kind of test exercises both the global EventDispatcher through
EventDispatcher.getInstance() and the per-GeckoView EventDispatcher
through GeckoApp.getEventDispatcher().
2016-11-14 13:29:50 +00:00
|
|
|
NS_IMPL_ISUPPORTS(nsWindow::AndroidView,
|
|
|
|
nsIAndroidEventDispatcher,
|
|
|
|
nsIAndroidView)
|
|
|
|
|
2017-02-16 23:26:20 +00:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsWindow::AndroidView::GetSettings(JSContext* aCx, JS::MutableHandleValue aOut)
|
|
|
|
{
|
|
|
|
if (!mSettings) {
|
|
|
|
aOut.setNull();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
JNIEnv* const env = jni::GetGeckoThreadEnv();
|
|
|
|
env->MonitorEnter(mSettings.Get());
|
|
|
|
nsresult rv = widget::EventDispatcher::UnboxBundle(aCx, mSettings, aOut);
|
|
|
|
env->MonitorExit(mSettings.Get());
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
/**
|
2016-08-01 18:21:31 +00:00
|
|
|
* Compositor has some unique requirements for its native calls, so make it
|
2015-12-24 03:03:34 +00:00
|
|
|
* separate from GeckoViewSupport.
|
|
|
|
*/
|
2016-08-01 18:21:31 +00:00
|
|
|
class nsWindow::LayerViewSupport final
|
|
|
|
: public LayerView::Compositor::Natives<LayerViewSupport>
|
2015-12-24 03:03:34 +00:00
|
|
|
{
|
2016-08-18 22:03:04 +00:00
|
|
|
using LockedWindowPtr = WindowPtr<LayerViewSupport>::Locked;
|
|
|
|
|
|
|
|
WindowPtr<LayerViewSupport> mWindow;
|
2016-08-01 18:21:31 +00:00
|
|
|
LayerView::Compositor::GlobalRef mCompositor;
|
2015-12-24 03:03:34 +00:00
|
|
|
GeckoLayerClient::GlobalRef mLayerClient;
|
|
|
|
Atomic<bool, ReleaseAcquire> mCompositorPaused;
|
2016-08-18 22:03:04 +00:00
|
|
|
jni::Object::GlobalRef mSurface;
|
2015-12-24 03:03:34 +00:00
|
|
|
|
2015-12-24 03:03:35 +00:00
|
|
|
// In order to use Event::HasSameTypeAs in PostTo(), we cannot make
|
2016-08-01 18:21:31 +00:00
|
|
|
// LayerViewEvent a template because each template instantiation is
|
|
|
|
// a different type. So implement LayerViewEvent as a ProxyEvent.
|
|
|
|
class LayerViewEvent final : public nsAppShell::ProxyEvent
|
2015-12-24 03:03:34 +00:00
|
|
|
{
|
|
|
|
using Event = nsAppShell::Event;
|
|
|
|
|
|
|
|
public:
|
2015-12-24 03:03:35 +00:00
|
|
|
static UniquePtr<Event> MakeEvent(UniquePtr<Event>&& event)
|
|
|
|
{
|
2016-08-01 18:21:31 +00:00
|
|
|
return MakeUnique<LayerViewEvent>(mozilla::Move(event));
|
2015-12-24 03:03:35 +00:00
|
|
|
}
|
|
|
|
|
2016-08-01 18:21:31 +00:00
|
|
|
LayerViewEvent(UniquePtr<Event>&& event)
|
2015-12-24 03:03:35 +00:00
|
|
|
: nsAppShell::ProxyEvent(mozilla::Move(event))
|
2015-12-24 03:03:34 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
void PostTo(LinkedList<Event>& queue) override
|
|
|
|
{
|
|
|
|
// Give priority to compositor events, but keep in order with
|
|
|
|
// existing compositor events.
|
|
|
|
nsAppShell::Event* event = queue.getFirst();
|
|
|
|
while (event && event->HasSameTypeAs(this)) {
|
|
|
|
event = event->getNext();
|
|
|
|
}
|
|
|
|
if (event) {
|
|
|
|
event->setPrevious(this);
|
|
|
|
} else {
|
|
|
|
queue.insertBack(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
public:
|
2016-08-01 18:21:31 +00:00
|
|
|
typedef LayerView::Compositor::Natives<LayerViewSupport> Base;
|
2015-12-24 03:03:34 +00:00
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
template<class Functor>
|
|
|
|
static void OnNativeCall(Functor&& aCall)
|
|
|
|
{
|
2016-08-01 18:21:31 +00:00
|
|
|
if (aCall.IsTarget(&LayerViewSupport::CreateCompositor)) {
|
|
|
|
// This call is blocking.
|
2016-08-26 16:25:57 +00:00
|
|
|
nsAppShell::SyncRunEvent(nsAppShell::LambdaEvent<Functor>(
|
2016-08-01 18:21:31 +00:00
|
|
|
mozilla::Move(aCall)), &LayerViewEvent::MakeEvent);
|
2015-12-24 03:03:34 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-19 21:17:24 +00:00
|
|
|
static LayerViewSupport*
|
|
|
|
FromNative(const LayerView::Compositor::LocalRef& instance)
|
|
|
|
{
|
|
|
|
return GetNative(instance);
|
|
|
|
}
|
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
LayerViewSupport(NativePtr<LayerViewSupport>* aPtr, nsWindow* aWindow,
|
2016-08-01 18:21:31 +00:00
|
|
|
const LayerView::Compositor::LocalRef& aInstance)
|
2016-08-18 22:03:04 +00:00
|
|
|
: mWindow(aPtr, aWindow)
|
2016-08-01 18:21:31 +00:00
|
|
|
, mCompositor(aInstance)
|
2015-12-24 03:03:34 +00:00
|
|
|
, mCompositorPaused(true)
|
2016-08-18 22:03:04 +00:00
|
|
|
{}
|
2015-12-24 03:03:34 +00:00
|
|
|
|
2016-08-01 18:21:31 +00:00
|
|
|
~LayerViewSupport()
|
2016-08-18 22:03:04 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
using Base::AttachNative;
|
|
|
|
using Base::DisposeNative;
|
|
|
|
|
|
|
|
void OnDetach()
|
2015-12-24 03:03:34 +00:00
|
|
|
{
|
2016-08-01 18:21:31 +00:00
|
|
|
mCompositor->Destroy();
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
const GeckoLayerClient::Ref& GetLayerClient() const
|
|
|
|
{
|
|
|
|
return mLayerClient;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CompositorPaused() const
|
|
|
|
{
|
|
|
|
return mCompositorPaused;
|
|
|
|
}
|
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
jni::Object::Param GetSurface()
|
2015-12-24 03:03:34 +00:00
|
|
|
{
|
2016-08-18 22:03:04 +00:00
|
|
|
return mSurface;
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
private:
|
2016-08-26 16:25:57 +00:00
|
|
|
void OnResumedCompositor()
|
2015-12-24 03:03:34 +00:00
|
|
|
{
|
2016-08-18 22:03:04 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
// When we receive this, the compositor has already been told to
|
|
|
|
// resume. (It turns out that waiting till we reach here to tell
|
|
|
|
// the compositor to resume takes too long, resulting in a black
|
|
|
|
// flash.) This means it's now safe for layer updates to occur.
|
|
|
|
// Since we might have prevented one or more draw events from
|
|
|
|
// occurring while the compositor was paused, we need to schedule
|
|
|
|
// a draw event now.
|
|
|
|
if (!mCompositorPaused) {
|
2016-08-18 22:03:04 +00:00
|
|
|
mWindow->RedrawAll();
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
/**
|
2016-08-01 18:21:31 +00:00
|
|
|
* Compositor methods
|
2015-12-24 03:03:34 +00:00
|
|
|
*/
|
|
|
|
public:
|
2016-01-15 18:05:45 +00:00
|
|
|
void AttachToJava(jni::Object::Param aClient, jni::Object::Param aNPZC)
|
2015-12-24 03:03:34 +00:00
|
|
|
{
|
2016-08-18 22:03:04 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-08-26 16:25:57 +00:00
|
|
|
if (!mWindow) {
|
|
|
|
return; // Already shut down.
|
|
|
|
}
|
2016-08-18 22:03:04 +00:00
|
|
|
|
2016-11-30 07:12:53 +00:00
|
|
|
mLayerClient = GeckoLayerClient::Ref::From(aClient);
|
2015-12-24 03:03:34 +00:00
|
|
|
|
2016-08-23 22:55:12 +00:00
|
|
|
MOZ_ASSERT(aNPZC);
|
|
|
|
auto npzc = NativePanZoomController::LocalRef(
|
|
|
|
jni::GetGeckoThreadEnv(),
|
|
|
|
NativePanZoomController::Ref::From(aNPZC));
|
|
|
|
mWindow->mNPZCSupport.Attach(npzc, mWindow, npzc);
|
|
|
|
|
2016-11-30 07:12:53 +00:00
|
|
|
mLayerClient->OnGeckoReady();
|
2016-08-23 22:55:12 +00:00
|
|
|
|
2016-11-30 07:12:53 +00:00
|
|
|
// Set the first-paint flag so that we (re-)link any new Java objects
|
|
|
|
// to Gecko, co-ordinate viewports, etc.
|
2017-01-05 19:11:41 +00:00
|
|
|
if (RefPtr<CompositorBridgeChild> bridge = mWindow->GetCompositorBridgeChild()) {
|
|
|
|
bridge->SendForceIsFirstPaint();
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
|
|
|
|
2016-02-01 22:38:14 +00:00
|
|
|
void OnSizeChanged(int32_t aWindowWidth, int32_t aWindowHeight,
|
|
|
|
int32_t aScreenWidth, int32_t aScreenHeight)
|
|
|
|
{
|
2016-08-18 22:03:04 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-08-26 16:25:57 +00:00
|
|
|
if (!mWindow) {
|
|
|
|
return; // Already shut down.
|
|
|
|
}
|
2016-08-18 22:03:04 +00:00
|
|
|
|
|
|
|
if (aWindowWidth != mWindow->mBounds.width ||
|
|
|
|
aWindowHeight != mWindow->mBounds.height) {
|
2016-02-01 22:38:14 +00:00
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
mWindow->Resize(aWindowWidth, aWindowHeight, /* repaint */ false);
|
2016-02-01 22:38:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-26 16:25:57 +00:00
|
|
|
void CreateCompositor(int32_t aWidth, int32_t aHeight,
|
|
|
|
jni::Object::Param aSurface)
|
2015-12-24 03:03:34 +00:00
|
|
|
{
|
2016-08-18 22:03:04 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-08-26 16:25:57 +00:00
|
|
|
MOZ_ASSERT(mWindow);
|
2016-08-18 22:03:04 +00:00
|
|
|
|
2016-08-26 16:25:57 +00:00
|
|
|
mSurface = aSurface;
|
2016-08-18 22:03:04 +00:00
|
|
|
mWindow->CreateLayerManager(aWidth, aHeight);
|
2016-08-26 16:25:57 +00:00
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
mCompositorPaused = false;
|
2016-08-26 16:25:57 +00:00
|
|
|
OnResumedCompositor();
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
void SyncPauseCompositor()
|
|
|
|
{
|
2016-08-18 22:03:04 +00:00
|
|
|
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
|
|
|
|
|
2017-01-05 19:11:41 +00:00
|
|
|
int64_t id = 0;
|
2016-08-18 22:03:04 +00:00
|
|
|
if (LockedWindowPtr window{mWindow}) {
|
2017-01-05 19:11:41 +00:00
|
|
|
id = window->GetRootLayerId();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (id == 0) {
|
|
|
|
return;
|
2016-08-18 22:03:04 +00:00
|
|
|
}
|
|
|
|
|
2017-01-05 19:11:41 +00:00
|
|
|
RefPtr<UiCompositorControllerChild> child = UiCompositorControllerChild::Get();
|
|
|
|
if (child) {
|
|
|
|
mCompositorPaused = true;
|
|
|
|
child->SendPause(id);
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SyncResumeCompositor()
|
|
|
|
{
|
2016-08-18 22:03:04 +00:00
|
|
|
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
|
|
|
|
|
2017-01-05 19:11:41 +00:00
|
|
|
int64_t id = 0;
|
2016-08-18 22:03:04 +00:00
|
|
|
if (LockedWindowPtr window{mWindow}) {
|
2017-01-05 19:11:41 +00:00
|
|
|
id = window->GetRootLayerId();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (id == 0) {
|
|
|
|
return;
|
2016-08-18 22:03:04 +00:00
|
|
|
}
|
|
|
|
|
2017-01-05 19:11:41 +00:00
|
|
|
RefPtr<UiCompositorControllerChild> child = UiCompositorControllerChild::Get();
|
|
|
|
if (child) {
|
|
|
|
mCompositorPaused = false;
|
|
|
|
child->SendResume(id);
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
|
|
|
|
2016-08-26 16:25:57 +00:00
|
|
|
void SyncResumeResizeCompositor(const LayerView::Compositor::LocalRef& aObj,
|
2016-08-26 16:25:57 +00:00
|
|
|
int32_t aWidth, int32_t aHeight,
|
|
|
|
jni::Object::Param aSurface)
|
2015-12-24 03:03:34 +00:00
|
|
|
{
|
2016-08-18 22:03:04 +00:00
|
|
|
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
|
|
|
|
|
2017-01-05 19:11:41 +00:00
|
|
|
mSurface = aSurface;
|
2016-08-18 22:03:04 +00:00
|
|
|
|
2017-01-05 19:11:41 +00:00
|
|
|
int64_t id = 0;
|
2016-08-18 22:03:04 +00:00
|
|
|
if (LockedWindowPtr window{mWindow}) {
|
2017-01-05 19:11:41 +00:00
|
|
|
id = window->GetRootLayerId();
|
2016-08-18 22:03:04 +00:00
|
|
|
}
|
|
|
|
|
2017-01-05 19:11:41 +00:00
|
|
|
if (id == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<UiCompositorControllerChild> child = UiCompositorControllerChild::Get();
|
2016-08-26 16:25:57 +00:00
|
|
|
|
2017-01-05 19:11:41 +00:00
|
|
|
if (!child) {
|
2017-02-07 22:44:43 +00:00
|
|
|
// When starting, sometimes the UiCompositorControllerChild is still initializing
|
|
|
|
// so cache the resized surface dimensions until it has initialized.
|
|
|
|
UiCompositorControllerChild::CacheSurfaceResize(id, aWidth, aHeight);
|
|
|
|
} else {
|
|
|
|
child->SendResumeAndResize(id, aWidth, aHeight);
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
2016-08-26 16:25:57 +00:00
|
|
|
|
|
|
|
mCompositorPaused = false;
|
|
|
|
|
|
|
|
class OnResumedEvent : public nsAppShell::Event
|
|
|
|
{
|
|
|
|
LayerView::Compositor::GlobalRef mCompositor;
|
|
|
|
|
|
|
|
public:
|
|
|
|
OnResumedEvent(LayerView::Compositor::GlobalRef&& aCompositor)
|
|
|
|
: mCompositor(mozilla::Move(aCompositor))
|
|
|
|
{}
|
|
|
|
|
|
|
|
void Run() override
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
JNIEnv* const env = jni::GetGeckoThreadEnv();
|
|
|
|
LayerViewSupport* const lvs = GetNative(
|
|
|
|
LayerView::Compositor::LocalRef(env, mCompositor));
|
|
|
|
MOZ_CATCH_JNI_EXCEPTION(env);
|
|
|
|
|
|
|
|
lvs->OnResumedCompositor();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
nsAppShell::PostEvent(MakeUnique<LayerViewEvent>(
|
|
|
|
MakeUnique<OnResumedEvent>(aObj)));
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SyncInvalidateAndScheduleComposite()
|
|
|
|
{
|
2017-01-05 19:11:41 +00:00
|
|
|
RefPtr<UiCompositorControllerChild> child = UiCompositorControllerChild::Get();
|
2016-08-18 22:03:04 +00:00
|
|
|
|
2017-01-05 19:11:41 +00:00
|
|
|
if (!child) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t id = 0;
|
2016-08-18 22:03:04 +00:00
|
|
|
if (LockedWindowPtr window{mWindow}) {
|
2017-01-05 19:11:41 +00:00
|
|
|
id = window->GetRootLayerId();
|
2016-08-18 22:03:04 +00:00
|
|
|
}
|
|
|
|
|
2017-01-05 19:11:41 +00:00
|
|
|
if (id == 0) {
|
|
|
|
return;
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
2017-01-05 19:11:41 +00:00
|
|
|
|
|
|
|
if (!AndroidBridge::IsJavaUiThread()) {
|
|
|
|
RefPtr<nsThread> uiThread = GetAndroidUiThread();
|
|
|
|
if (uiThread) {
|
|
|
|
uiThread->Dispatch(NewRunnableMethod<const int64_t&>(child,
|
|
|
|
&UiCompositorControllerChild::SendInvalidateAndRender,
|
|
|
|
id),
|
|
|
|
nsIThread::DISPATCH_NORMAL);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
|
|
|
|
child->SendInvalidateAndRender(id);
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
template<> const char
|
|
|
|
nsWindow::NativePtr<nsWindow::LayerViewSupport>::sName[] = "LayerViewSupport";
|
2016-08-01 18:21:31 +00:00
|
|
|
|
2016-08-19 21:17:24 +00:00
|
|
|
/* PresentationMediaPlayerManager native calls access inner nsWindow functionality so PMPMSupport is a child class of nsWindow */
|
|
|
|
class nsWindow::PMPMSupport final
|
|
|
|
: public PresentationMediaPlayerManager::Natives<PMPMSupport>
|
|
|
|
{
|
|
|
|
PMPMSupport() = delete;
|
|
|
|
|
|
|
|
static LayerViewSupport* GetLayerViewSupport(jni::Object::Param aView)
|
|
|
|
{
|
|
|
|
const auto& layerView = LayerView::Ref::From(aView);
|
|
|
|
|
|
|
|
LayerView::Compositor::LocalRef compositor = layerView->GetCompositor();
|
|
|
|
if (!layerView->CompositorCreated() || !compositor) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
LayerViewSupport* const lvs = LayerViewSupport::FromNative(compositor);
|
|
|
|
if (!lvs) {
|
|
|
|
// There is a pending exception whenever FromNative returns nullptr.
|
|
|
|
compositor.Env()->ExceptionClear();
|
|
|
|
}
|
|
|
|
return lvs;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
static ANativeWindow* sWindow;
|
|
|
|
static EGLSurface sSurface;
|
|
|
|
|
|
|
|
static void InvalidateAndScheduleComposite(jni::Object::Param aView)
|
|
|
|
{
|
|
|
|
LayerViewSupport* const lvs = GetLayerViewSupport(aView);
|
|
|
|
if (lvs) {
|
|
|
|
lvs->SyncInvalidateAndScheduleComposite();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void AddPresentationSurface(const jni::Class::LocalRef& aCls,
|
|
|
|
jni::Object::Param aView,
|
|
|
|
jni::Object::Param aSurface)
|
|
|
|
{
|
|
|
|
RemovePresentationSurface();
|
|
|
|
|
|
|
|
LayerViewSupport* const lvs = GetLayerViewSupport(aView);
|
|
|
|
if (!lvs) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ANativeWindow* const window = ANativeWindow_fromSurface(
|
|
|
|
aCls.Env(), aSurface.Get());
|
|
|
|
if (!window) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sWindow = window;
|
|
|
|
|
|
|
|
const bool wasAlreadyPaused = lvs->CompositorPaused();
|
|
|
|
if (!wasAlreadyPaused) {
|
|
|
|
lvs->SyncPauseCompositor();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sSurface) {
|
|
|
|
// Destroy the EGL surface! The compositor is paused so it should
|
|
|
|
// be okay to destroy the surface here.
|
|
|
|
mozilla::gl::GLContextProvider::DestroyEGLSurface(sSurface);
|
|
|
|
sSurface = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!wasAlreadyPaused) {
|
|
|
|
lvs->SyncResumeCompositor();
|
|
|
|
}
|
|
|
|
|
|
|
|
lvs->SyncInvalidateAndScheduleComposite();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void RemovePresentationSurface()
|
|
|
|
{
|
|
|
|
if (sWindow) {
|
|
|
|
ANativeWindow_release(sWindow);
|
|
|
|
sWindow = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
ANativeWindow* nsWindow::PMPMSupport::sWindow;
|
|
|
|
EGLSurface nsWindow::PMPMSupport::sSurface;
|
|
|
|
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
nsWindow::GeckoViewSupport::~GeckoViewSupport()
|
2015-10-22 21:45:46 +00:00
|
|
|
{
|
|
|
|
// Disassociate our GeckoEditable instance with our native object.
|
2015-10-22 21:45:47 +00:00
|
|
|
// OnDestroy will call disposeNative after any pending native calls have
|
|
|
|
// been made.
|
2015-10-22 21:45:46 +00:00
|
|
|
MOZ_ASSERT(mEditable);
|
2016-01-07 02:33:18 +00:00
|
|
|
mEditable->OnViewChange(nullptr);
|
2016-08-18 22:03:04 +00:00
|
|
|
|
|
|
|
if (window.mNPZCSupport) {
|
|
|
|
window.mNPZCSupport.Detach();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window.mLayerViewSupport) {
|
|
|
|
window.mLayerViewSupport.Detach();
|
|
|
|
}
|
2015-10-22 21:45:46 +00:00
|
|
|
}
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
/* static */ void
|
2016-02-09 22:27:28 +00:00
|
|
|
nsWindow::GeckoViewSupport::Open(const jni::Class::LocalRef& aCls,
|
2015-12-24 03:03:34 +00:00
|
|
|
GeckoView::Window::Param aWindow,
|
|
|
|
GeckoView::Param aView,
|
2016-08-01 18:21:31 +00:00
|
|
|
jni::Object::Param aCompositor,
|
Bug 1307820 - Implement per-GeckoView messaging; r=snorp r=sebastian
Bug 1307820 - 1a. Move GeckoApp EventDispatcher to GeckoView; r=snorp
Make it a GeckoView-specific EventDispatcher instead of
GeckoApp-specific, so that GeckoView consumers can benefit from a
per-view EventDispatcher. In addition, a few events like Gecko:Ready are
moved back to the global EventDispatcher because that makes more sense.
Bug 1307820 - 1b. Don't use GeckoApp EventDispatcher during inflation; r=snorp
During layout inflation, we don't yet have GeckoView and therefore the
GeckoView EventDispatcher, so we should not register events until later,
typically during onAttachedToWindow.
Bug 1307820 - 2. Introduce GeckoBundle; r=snorp
The Android Bundle class has several disadvantages when used for holding
structured data from JS.
The most obvious one is the differentiation between int and double,
which doesn't exist in JS. So when a JS number is converted to either a
Bundle int or double, we run the risk of making a wrong conversion,
resulting in a type mismatch exception when Java uses the Bundle. This
extends to number arrays from JS.
There is one more gotcha when using arrays. When we receive an empty
array from JS, there is no way for us to determine the type of the
array, because even empty arrays in Java have types. We are forced to
pick an arbitrary type like boolean[], which can easily result in a type
mismatch exception when using the array on the Java side.
In addition, Bundle is fairly cumbersome, and we cannot access the inner
structures of Bundle from Java or JNI, making it harder to use.
With these factors in mind, this patch introduces GeckoBundle as a
better choice for Gecko/Java communication. It is almost fully
API-compatible with the Android Bundle; only the Bundle array methods
are different. It resolves the numbers problem by performing conversions
if necessary, and it is a lot more lightweight than Bundle.
Bug 1307820 - 3. Convert BundleEventListener to use GeckoBundle; r=snorp
Convert BundleEventListener from using Bundle to using GeckoBundle.
Because NativeJSContainer still only supports Bundle, we do an extra
conversion when sending Bundle messages, but eventually, as we eliminate
the use of NativeJSContainer, that will go away as well.
Bug 1307820 - 4. Introduce EventDispatcher interfaces; r=snorp
Introduce several new XPCOM interfaces for the new EventDispatcher API,
these interfaces are mostly mirrored after their Java counterparts.
* nsIAndroidEventDispatcher is the main interface for
registering/unregistering listeners and for dispatching events from
JS/C++.
* nsIAndroidEventListener is the interface that JS/C++ clients implement
to receive events.
* nsIAndroidEventCallback is the interface that JS/C++ clients implement
to receive responses from dispatched events.
* nsIAndroidView is the new interface that every window receives
that is specific to the window/GeckoView pair. It is passed to chrome
scripts through window arguments.
Bug 1307820 - 5. Remove EventDispatcher references from gfx code; r=snorp
EventDispatcher was used for JPZC, but NPZC doesn't use it anymore.
Bug 1307820 - 6. General JNI template improvements; r=snorp
This patch includes several improvements to the JNI templates.
* Context::RawClassRef is removed to avoid misuse, as Context::ClassRef
should be used instead.
* Fix a compile error, in certain usages, in the DisposeNative overload
in NativeStub.
* Add Ref::IsInstanceOf and Context::IsInstanceOf to mirror the
JNIEnv::IsInstanceOf call.
* Add Ref::operator* and Context::operator* to provide an easy way to
get a Context object.
* Add built-in declarations for boxed Java objects (e.g. Boolean,
Integer, etc).
* Add ObjectArray::New for creating new object arrays of specific types.
* Add lvalue qualifiers to LocalRef::operator= and GlobalRef::operator=,
to prevent accidentally assigning to rvalues. (e.g.
`objectArray->GetElement(0) = newObject;`, which won't work as intended.)
Bug 1307820 - 7. Support ownership through RefPtr for native JNI objects; r=snorp
In addition to direct ownership and weak pointer ownership, add a third
ownership model where a native JNI object owns a RefPtr that holds a
strong reference to the actual C++ object. This ownership model works
well with ref-counted objects such as XPCOM objects, and is activated
through the presence of public members AddRef() and Release() in the C++
object.
Bug 1307820 - 8. Implement Gecko-side EventDispatcher; r=snorp
Add a skeletal implementation of EventDispatcher on the Gecko side.
Each widget::EventDispatcher will be associated with a Java
EventDispatcher, so events can be dispatched from Gecko to Java and vice
versa. AndroidBridge and nsWindow will implement
nsIAndroidEventDispatcher through widget::EventDispatcher.
Other patches will add more complete functionality such as
GeckoBundle/JSObject translation and support for callbacks.
Bug 1307820 - 9. Implement dispatching between Gecko/Java; r=snorp
Implement translation between JSObject and GeckoBundle, and use that for
dispatching events from Gecko to Java and vice versa.
Bug 1307820 - 10. Implement callback support; r=snorp
Implement callback support for both Gecko-to-Java events and
Java-to-Gecko events.
For Gecko-to-Java, we translate nsIAndroidEventCallback to a Java
EventCallback through NativeCallbackDelegate and pass it to the Java
listener.
For Java-to-Gecko, we translate EventCallback to a
nsIAndroidEventCallback through JavaCallbackDelegate and pass it to the
Gecko listener. There is another JavaCallbackDelegate on the Java side
that redirects the callback to a particular thread. For example, if the
event was dispatched from the UI thread, we make sure the callback
happens on the UI thread as well.
Bug 1307820 - 11. Add BundleEventListener support for Gecko thread; r=snorp
Add support for BundleEventListener on the Gecko thread, so that we can
use it to replace any existing GeckoEventListener or NativeEventListener
implementations that require the listener be run synchronously on the
Gecko thread.
Bug 1307820 - 12. Add global EventDispatcher in AndroidBridge; r=snorp
Add an instance of EventDispatcher to AndroidBridge to act as a global
event dispatcher.
Bug 1307820 - 13. Add per-nsWindow EventDispatcher; r=snorp
Add an instance of EventDispatcher to each nsWindow through an
AndroidView object, which implements nsIAndroidView. The nsIAndroidView
is passed to the chrome script through the window argument when opening
the window.
Bug 1307820 - 14. Update auto-generated bindings; r=me
Bug 1307820 - 15. Update testEventDispatcher; r=snorp
Update testEventDispatcher to include new functionalities in
EventDisptcher.
* Add tests for dispatching events to UI/background thread through
nsIAndroidEventDispatcher::dispatch.
* Add tests for dispatching events to UI/background thread through
EventDispatcher.dispatch.
* Add tests for dispatching events to Gecko thread through
EventDispatcher.dispatch.
Each kind of test exercises both the global EventDispatcher through
EventDispatcher.getInstance() and the per-GeckoView EventDispatcher
through GeckoApp.getEventDispatcher().
2016-11-14 13:29:50 +00:00
|
|
|
jni::Object::Param aDispatcher,
|
2016-09-29 06:23:56 +00:00
|
|
|
jni::String::Param aChromeURI,
|
2017-02-16 23:26:20 +00:00
|
|
|
jni::Object::Param aSettings,
|
2016-09-29 06:23:56 +00:00
|
|
|
int32_t aScreenId)
|
2015-09-21 14:13:32 +00:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
PROFILER_LABEL("nsWindow", "GeckoViewSupport::Open",
|
2015-09-21 14:13:32 +00:00
|
|
|
js::ProfileEntry::Category::OTHER);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIWindowWatcher> ww = do_GetService(NS_WINDOWWATCHER_CONTRACTID);
|
2016-07-21 01:43:34 +00:00
|
|
|
MOZ_RELEASE_ASSERT(ww);
|
2015-09-21 14:13:32 +00:00
|
|
|
|
2016-06-23 19:05:17 +00:00
|
|
|
nsAdoptingCString url;
|
|
|
|
if (aChromeURI) {
|
|
|
|
url = aChromeURI->ToCString();
|
|
|
|
} else {
|
|
|
|
url = Preferences::GetCString("toolkit.defaultChromeURI");
|
|
|
|
if (!url) {
|
|
|
|
url = NS_LITERAL_CSTRING("chrome://browser/content/browser.xul");
|
|
|
|
}
|
2015-09-21 14:13:32 +00:00
|
|
|
}
|
|
|
|
|
Bug 1307820 - Implement per-GeckoView messaging; r=snorp r=sebastian
Bug 1307820 - 1a. Move GeckoApp EventDispatcher to GeckoView; r=snorp
Make it a GeckoView-specific EventDispatcher instead of
GeckoApp-specific, so that GeckoView consumers can benefit from a
per-view EventDispatcher. In addition, a few events like Gecko:Ready are
moved back to the global EventDispatcher because that makes more sense.
Bug 1307820 - 1b. Don't use GeckoApp EventDispatcher during inflation; r=snorp
During layout inflation, we don't yet have GeckoView and therefore the
GeckoView EventDispatcher, so we should not register events until later,
typically during onAttachedToWindow.
Bug 1307820 - 2. Introduce GeckoBundle; r=snorp
The Android Bundle class has several disadvantages when used for holding
structured data from JS.
The most obvious one is the differentiation between int and double,
which doesn't exist in JS. So when a JS number is converted to either a
Bundle int or double, we run the risk of making a wrong conversion,
resulting in a type mismatch exception when Java uses the Bundle. This
extends to number arrays from JS.
There is one more gotcha when using arrays. When we receive an empty
array from JS, there is no way for us to determine the type of the
array, because even empty arrays in Java have types. We are forced to
pick an arbitrary type like boolean[], which can easily result in a type
mismatch exception when using the array on the Java side.
In addition, Bundle is fairly cumbersome, and we cannot access the inner
structures of Bundle from Java or JNI, making it harder to use.
With these factors in mind, this patch introduces GeckoBundle as a
better choice for Gecko/Java communication. It is almost fully
API-compatible with the Android Bundle; only the Bundle array methods
are different. It resolves the numbers problem by performing conversions
if necessary, and it is a lot more lightweight than Bundle.
Bug 1307820 - 3. Convert BundleEventListener to use GeckoBundle; r=snorp
Convert BundleEventListener from using Bundle to using GeckoBundle.
Because NativeJSContainer still only supports Bundle, we do an extra
conversion when sending Bundle messages, but eventually, as we eliminate
the use of NativeJSContainer, that will go away as well.
Bug 1307820 - 4. Introduce EventDispatcher interfaces; r=snorp
Introduce several new XPCOM interfaces for the new EventDispatcher API,
these interfaces are mostly mirrored after their Java counterparts.
* nsIAndroidEventDispatcher is the main interface for
registering/unregistering listeners and for dispatching events from
JS/C++.
* nsIAndroidEventListener is the interface that JS/C++ clients implement
to receive events.
* nsIAndroidEventCallback is the interface that JS/C++ clients implement
to receive responses from dispatched events.
* nsIAndroidView is the new interface that every window receives
that is specific to the window/GeckoView pair. It is passed to chrome
scripts through window arguments.
Bug 1307820 - 5. Remove EventDispatcher references from gfx code; r=snorp
EventDispatcher was used for JPZC, but NPZC doesn't use it anymore.
Bug 1307820 - 6. General JNI template improvements; r=snorp
This patch includes several improvements to the JNI templates.
* Context::RawClassRef is removed to avoid misuse, as Context::ClassRef
should be used instead.
* Fix a compile error, in certain usages, in the DisposeNative overload
in NativeStub.
* Add Ref::IsInstanceOf and Context::IsInstanceOf to mirror the
JNIEnv::IsInstanceOf call.
* Add Ref::operator* and Context::operator* to provide an easy way to
get a Context object.
* Add built-in declarations for boxed Java objects (e.g. Boolean,
Integer, etc).
* Add ObjectArray::New for creating new object arrays of specific types.
* Add lvalue qualifiers to LocalRef::operator= and GlobalRef::operator=,
to prevent accidentally assigning to rvalues. (e.g.
`objectArray->GetElement(0) = newObject;`, which won't work as intended.)
Bug 1307820 - 7. Support ownership through RefPtr for native JNI objects; r=snorp
In addition to direct ownership and weak pointer ownership, add a third
ownership model where a native JNI object owns a RefPtr that holds a
strong reference to the actual C++ object. This ownership model works
well with ref-counted objects such as XPCOM objects, and is activated
through the presence of public members AddRef() and Release() in the C++
object.
Bug 1307820 - 8. Implement Gecko-side EventDispatcher; r=snorp
Add a skeletal implementation of EventDispatcher on the Gecko side.
Each widget::EventDispatcher will be associated with a Java
EventDispatcher, so events can be dispatched from Gecko to Java and vice
versa. AndroidBridge and nsWindow will implement
nsIAndroidEventDispatcher through widget::EventDispatcher.
Other patches will add more complete functionality such as
GeckoBundle/JSObject translation and support for callbacks.
Bug 1307820 - 9. Implement dispatching between Gecko/Java; r=snorp
Implement translation between JSObject and GeckoBundle, and use that for
dispatching events from Gecko to Java and vice versa.
Bug 1307820 - 10. Implement callback support; r=snorp
Implement callback support for both Gecko-to-Java events and
Java-to-Gecko events.
For Gecko-to-Java, we translate nsIAndroidEventCallback to a Java
EventCallback through NativeCallbackDelegate and pass it to the Java
listener.
For Java-to-Gecko, we translate EventCallback to a
nsIAndroidEventCallback through JavaCallbackDelegate and pass it to the
Gecko listener. There is another JavaCallbackDelegate on the Java side
that redirects the callback to a particular thread. For example, if the
event was dispatched from the UI thread, we make sure the callback
happens on the UI thread as well.
Bug 1307820 - 11. Add BundleEventListener support for Gecko thread; r=snorp
Add support for BundleEventListener on the Gecko thread, so that we can
use it to replace any existing GeckoEventListener or NativeEventListener
implementations that require the listener be run synchronously on the
Gecko thread.
Bug 1307820 - 12. Add global EventDispatcher in AndroidBridge; r=snorp
Add an instance of EventDispatcher to AndroidBridge to act as a global
event dispatcher.
Bug 1307820 - 13. Add per-nsWindow EventDispatcher; r=snorp
Add an instance of EventDispatcher to each nsWindow through an
AndroidView object, which implements nsIAndroidView. The nsIAndroidView
is passed to the chrome script through the window argument when opening
the window.
Bug 1307820 - 14. Update auto-generated bindings; r=me
Bug 1307820 - 15. Update testEventDispatcher; r=snorp
Update testEventDispatcher to include new functionalities in
EventDisptcher.
* Add tests for dispatching events to UI/background thread through
nsIAndroidEventDispatcher::dispatch.
* Add tests for dispatching events to UI/background thread through
EventDispatcher.dispatch.
* Add tests for dispatching events to Gecko thread through
EventDispatcher.dispatch.
Each kind of test exercises both the global EventDispatcher through
EventDispatcher.getInstance() and the per-GeckoView EventDispatcher
through GeckoApp.getEventDispatcher().
2016-11-14 13:29:50 +00:00
|
|
|
RefPtr<AndroidView> androidView = new AndroidView();
|
|
|
|
androidView->mEventDispatcher->Attach(
|
|
|
|
java::EventDispatcher::Ref::From(aDispatcher), nullptr);
|
2017-02-16 23:26:20 +00:00
|
|
|
if (aSettings) {
|
|
|
|
androidView->mSettings = java::GeckoBundle::Ref::From(aSettings);
|
|
|
|
}
|
Bug 1307820 - Implement per-GeckoView messaging; r=snorp r=sebastian
Bug 1307820 - 1a. Move GeckoApp EventDispatcher to GeckoView; r=snorp
Make it a GeckoView-specific EventDispatcher instead of
GeckoApp-specific, so that GeckoView consumers can benefit from a
per-view EventDispatcher. In addition, a few events like Gecko:Ready are
moved back to the global EventDispatcher because that makes more sense.
Bug 1307820 - 1b. Don't use GeckoApp EventDispatcher during inflation; r=snorp
During layout inflation, we don't yet have GeckoView and therefore the
GeckoView EventDispatcher, so we should not register events until later,
typically during onAttachedToWindow.
Bug 1307820 - 2. Introduce GeckoBundle; r=snorp
The Android Bundle class has several disadvantages when used for holding
structured data from JS.
The most obvious one is the differentiation between int and double,
which doesn't exist in JS. So when a JS number is converted to either a
Bundle int or double, we run the risk of making a wrong conversion,
resulting in a type mismatch exception when Java uses the Bundle. This
extends to number arrays from JS.
There is one more gotcha when using arrays. When we receive an empty
array from JS, there is no way for us to determine the type of the
array, because even empty arrays in Java have types. We are forced to
pick an arbitrary type like boolean[], which can easily result in a type
mismatch exception when using the array on the Java side.
In addition, Bundle is fairly cumbersome, and we cannot access the inner
structures of Bundle from Java or JNI, making it harder to use.
With these factors in mind, this patch introduces GeckoBundle as a
better choice for Gecko/Java communication. It is almost fully
API-compatible with the Android Bundle; only the Bundle array methods
are different. It resolves the numbers problem by performing conversions
if necessary, and it is a lot more lightweight than Bundle.
Bug 1307820 - 3. Convert BundleEventListener to use GeckoBundle; r=snorp
Convert BundleEventListener from using Bundle to using GeckoBundle.
Because NativeJSContainer still only supports Bundle, we do an extra
conversion when sending Bundle messages, but eventually, as we eliminate
the use of NativeJSContainer, that will go away as well.
Bug 1307820 - 4. Introduce EventDispatcher interfaces; r=snorp
Introduce several new XPCOM interfaces for the new EventDispatcher API,
these interfaces are mostly mirrored after their Java counterparts.
* nsIAndroidEventDispatcher is the main interface for
registering/unregistering listeners and for dispatching events from
JS/C++.
* nsIAndroidEventListener is the interface that JS/C++ clients implement
to receive events.
* nsIAndroidEventCallback is the interface that JS/C++ clients implement
to receive responses from dispatched events.
* nsIAndroidView is the new interface that every window receives
that is specific to the window/GeckoView pair. It is passed to chrome
scripts through window arguments.
Bug 1307820 - 5. Remove EventDispatcher references from gfx code; r=snorp
EventDispatcher was used for JPZC, but NPZC doesn't use it anymore.
Bug 1307820 - 6. General JNI template improvements; r=snorp
This patch includes several improvements to the JNI templates.
* Context::RawClassRef is removed to avoid misuse, as Context::ClassRef
should be used instead.
* Fix a compile error, in certain usages, in the DisposeNative overload
in NativeStub.
* Add Ref::IsInstanceOf and Context::IsInstanceOf to mirror the
JNIEnv::IsInstanceOf call.
* Add Ref::operator* and Context::operator* to provide an easy way to
get a Context object.
* Add built-in declarations for boxed Java objects (e.g. Boolean,
Integer, etc).
* Add ObjectArray::New for creating new object arrays of specific types.
* Add lvalue qualifiers to LocalRef::operator= and GlobalRef::operator=,
to prevent accidentally assigning to rvalues. (e.g.
`objectArray->GetElement(0) = newObject;`, which won't work as intended.)
Bug 1307820 - 7. Support ownership through RefPtr for native JNI objects; r=snorp
In addition to direct ownership and weak pointer ownership, add a third
ownership model where a native JNI object owns a RefPtr that holds a
strong reference to the actual C++ object. This ownership model works
well with ref-counted objects such as XPCOM objects, and is activated
through the presence of public members AddRef() and Release() in the C++
object.
Bug 1307820 - 8. Implement Gecko-side EventDispatcher; r=snorp
Add a skeletal implementation of EventDispatcher on the Gecko side.
Each widget::EventDispatcher will be associated with a Java
EventDispatcher, so events can be dispatched from Gecko to Java and vice
versa. AndroidBridge and nsWindow will implement
nsIAndroidEventDispatcher through widget::EventDispatcher.
Other patches will add more complete functionality such as
GeckoBundle/JSObject translation and support for callbacks.
Bug 1307820 - 9. Implement dispatching between Gecko/Java; r=snorp
Implement translation between JSObject and GeckoBundle, and use that for
dispatching events from Gecko to Java and vice versa.
Bug 1307820 - 10. Implement callback support; r=snorp
Implement callback support for both Gecko-to-Java events and
Java-to-Gecko events.
For Gecko-to-Java, we translate nsIAndroidEventCallback to a Java
EventCallback through NativeCallbackDelegate and pass it to the Java
listener.
For Java-to-Gecko, we translate EventCallback to a
nsIAndroidEventCallback through JavaCallbackDelegate and pass it to the
Gecko listener. There is another JavaCallbackDelegate on the Java side
that redirects the callback to a particular thread. For example, if the
event was dispatched from the UI thread, we make sure the callback
happens on the UI thread as well.
Bug 1307820 - 11. Add BundleEventListener support for Gecko thread; r=snorp
Add support for BundleEventListener on the Gecko thread, so that we can
use it to replace any existing GeckoEventListener or NativeEventListener
implementations that require the listener be run synchronously on the
Gecko thread.
Bug 1307820 - 12. Add global EventDispatcher in AndroidBridge; r=snorp
Add an instance of EventDispatcher to AndroidBridge to act as a global
event dispatcher.
Bug 1307820 - 13. Add per-nsWindow EventDispatcher; r=snorp
Add an instance of EventDispatcher to each nsWindow through an
AndroidView object, which implements nsIAndroidView. The nsIAndroidView
is passed to the chrome script through the window argument when opening
the window.
Bug 1307820 - 14. Update auto-generated bindings; r=me
Bug 1307820 - 15. Update testEventDispatcher; r=snorp
Update testEventDispatcher to include new functionalities in
EventDisptcher.
* Add tests for dispatching events to UI/background thread through
nsIAndroidEventDispatcher::dispatch.
* Add tests for dispatching events to UI/background thread through
EventDispatcher.dispatch.
* Add tests for dispatching events to Gecko thread through
EventDispatcher.dispatch.
Each kind of test exercises both the global EventDispatcher through
EventDispatcher.getInstance() and the per-GeckoView EventDispatcher
through GeckoApp.getEventDispatcher().
2016-11-14 13:29:50 +00:00
|
|
|
|
2016-01-30 17:05:36 +00:00
|
|
|
nsCOMPtr<mozIDOMWindowProxy> domWindow;
|
2016-10-07 15:22:34 +00:00
|
|
|
ww->OpenWindow(nullptr, url, nullptr, "chrome,dialog=0,resizable,scrollbars=yes",
|
Bug 1307820 - Implement per-GeckoView messaging; r=snorp r=sebastian
Bug 1307820 - 1a. Move GeckoApp EventDispatcher to GeckoView; r=snorp
Make it a GeckoView-specific EventDispatcher instead of
GeckoApp-specific, so that GeckoView consumers can benefit from a
per-view EventDispatcher. In addition, a few events like Gecko:Ready are
moved back to the global EventDispatcher because that makes more sense.
Bug 1307820 - 1b. Don't use GeckoApp EventDispatcher during inflation; r=snorp
During layout inflation, we don't yet have GeckoView and therefore the
GeckoView EventDispatcher, so we should not register events until later,
typically during onAttachedToWindow.
Bug 1307820 - 2. Introduce GeckoBundle; r=snorp
The Android Bundle class has several disadvantages when used for holding
structured data from JS.
The most obvious one is the differentiation between int and double,
which doesn't exist in JS. So when a JS number is converted to either a
Bundle int or double, we run the risk of making a wrong conversion,
resulting in a type mismatch exception when Java uses the Bundle. This
extends to number arrays from JS.
There is one more gotcha when using arrays. When we receive an empty
array from JS, there is no way for us to determine the type of the
array, because even empty arrays in Java have types. We are forced to
pick an arbitrary type like boolean[], which can easily result in a type
mismatch exception when using the array on the Java side.
In addition, Bundle is fairly cumbersome, and we cannot access the inner
structures of Bundle from Java or JNI, making it harder to use.
With these factors in mind, this patch introduces GeckoBundle as a
better choice for Gecko/Java communication. It is almost fully
API-compatible with the Android Bundle; only the Bundle array methods
are different. It resolves the numbers problem by performing conversions
if necessary, and it is a lot more lightweight than Bundle.
Bug 1307820 - 3. Convert BundleEventListener to use GeckoBundle; r=snorp
Convert BundleEventListener from using Bundle to using GeckoBundle.
Because NativeJSContainer still only supports Bundle, we do an extra
conversion when sending Bundle messages, but eventually, as we eliminate
the use of NativeJSContainer, that will go away as well.
Bug 1307820 - 4. Introduce EventDispatcher interfaces; r=snorp
Introduce several new XPCOM interfaces for the new EventDispatcher API,
these interfaces are mostly mirrored after their Java counterparts.
* nsIAndroidEventDispatcher is the main interface for
registering/unregistering listeners and for dispatching events from
JS/C++.
* nsIAndroidEventListener is the interface that JS/C++ clients implement
to receive events.
* nsIAndroidEventCallback is the interface that JS/C++ clients implement
to receive responses from dispatched events.
* nsIAndroidView is the new interface that every window receives
that is specific to the window/GeckoView pair. It is passed to chrome
scripts through window arguments.
Bug 1307820 - 5. Remove EventDispatcher references from gfx code; r=snorp
EventDispatcher was used for JPZC, but NPZC doesn't use it anymore.
Bug 1307820 - 6. General JNI template improvements; r=snorp
This patch includes several improvements to the JNI templates.
* Context::RawClassRef is removed to avoid misuse, as Context::ClassRef
should be used instead.
* Fix a compile error, in certain usages, in the DisposeNative overload
in NativeStub.
* Add Ref::IsInstanceOf and Context::IsInstanceOf to mirror the
JNIEnv::IsInstanceOf call.
* Add Ref::operator* and Context::operator* to provide an easy way to
get a Context object.
* Add built-in declarations for boxed Java objects (e.g. Boolean,
Integer, etc).
* Add ObjectArray::New for creating new object arrays of specific types.
* Add lvalue qualifiers to LocalRef::operator= and GlobalRef::operator=,
to prevent accidentally assigning to rvalues. (e.g.
`objectArray->GetElement(0) = newObject;`, which won't work as intended.)
Bug 1307820 - 7. Support ownership through RefPtr for native JNI objects; r=snorp
In addition to direct ownership and weak pointer ownership, add a third
ownership model where a native JNI object owns a RefPtr that holds a
strong reference to the actual C++ object. This ownership model works
well with ref-counted objects such as XPCOM objects, and is activated
through the presence of public members AddRef() and Release() in the C++
object.
Bug 1307820 - 8. Implement Gecko-side EventDispatcher; r=snorp
Add a skeletal implementation of EventDispatcher on the Gecko side.
Each widget::EventDispatcher will be associated with a Java
EventDispatcher, so events can be dispatched from Gecko to Java and vice
versa. AndroidBridge and nsWindow will implement
nsIAndroidEventDispatcher through widget::EventDispatcher.
Other patches will add more complete functionality such as
GeckoBundle/JSObject translation and support for callbacks.
Bug 1307820 - 9. Implement dispatching between Gecko/Java; r=snorp
Implement translation between JSObject and GeckoBundle, and use that for
dispatching events from Gecko to Java and vice versa.
Bug 1307820 - 10. Implement callback support; r=snorp
Implement callback support for both Gecko-to-Java events and
Java-to-Gecko events.
For Gecko-to-Java, we translate nsIAndroidEventCallback to a Java
EventCallback through NativeCallbackDelegate and pass it to the Java
listener.
For Java-to-Gecko, we translate EventCallback to a
nsIAndroidEventCallback through JavaCallbackDelegate and pass it to the
Gecko listener. There is another JavaCallbackDelegate on the Java side
that redirects the callback to a particular thread. For example, if the
event was dispatched from the UI thread, we make sure the callback
happens on the UI thread as well.
Bug 1307820 - 11. Add BundleEventListener support for Gecko thread; r=snorp
Add support for BundleEventListener on the Gecko thread, so that we can
use it to replace any existing GeckoEventListener or NativeEventListener
implementations that require the listener be run synchronously on the
Gecko thread.
Bug 1307820 - 12. Add global EventDispatcher in AndroidBridge; r=snorp
Add an instance of EventDispatcher to AndroidBridge to act as a global
event dispatcher.
Bug 1307820 - 13. Add per-nsWindow EventDispatcher; r=snorp
Add an instance of EventDispatcher to each nsWindow through an
AndroidView object, which implements nsIAndroidView. The nsIAndroidView
is passed to the chrome script through the window argument when opening
the window.
Bug 1307820 - 14. Update auto-generated bindings; r=me
Bug 1307820 - 15. Update testEventDispatcher; r=snorp
Update testEventDispatcher to include new functionalities in
EventDisptcher.
* Add tests for dispatching events to UI/background thread through
nsIAndroidEventDispatcher::dispatch.
* Add tests for dispatching events to UI/background thread through
EventDispatcher.dispatch.
* Add tests for dispatching events to Gecko thread through
EventDispatcher.dispatch.
Each kind of test exercises both the global EventDispatcher through
EventDispatcher.getInstance() and the per-GeckoView EventDispatcher
through GeckoApp.getEventDispatcher().
2016-11-14 13:29:50 +00:00
|
|
|
androidView, getter_AddRefs(domWindow));
|
2016-07-21 01:43:34 +00:00
|
|
|
MOZ_RELEASE_ASSERT(domWindow);
|
2015-09-21 14:13:32 +00:00
|
|
|
|
2016-07-21 01:43:34 +00:00
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> pdomWindow =
|
|
|
|
nsPIDOMWindowOuter::From(domWindow);
|
|
|
|
nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(pdomWindow);
|
2015-09-21 14:13:32 +00:00
|
|
|
MOZ_ASSERT(widget);
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
const auto window = static_cast<nsWindow*>(widget.get());
|
2016-09-29 06:23:56 +00:00
|
|
|
window->SetScreenId(aScreenId);
|
2015-10-08 19:25:49 +00:00
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
// Attach a new GeckoView support object to the new window.
|
|
|
|
window->mGeckoViewSupport = mozilla::MakeUnique<GeckoViewSupport>(
|
|
|
|
window, GeckoView::Window::LocalRef(aCls.Env(), aWindow), aView);
|
2015-10-08 19:25:49 +00:00
|
|
|
|
2016-07-21 01:43:34 +00:00
|
|
|
window->mGeckoViewSupport->mDOMWindow = pdomWindow;
|
|
|
|
|
2016-08-01 18:21:31 +00:00
|
|
|
// Attach the Compositor to the new window.
|
2016-08-18 22:03:04 +00:00
|
|
|
auto compositor = LayerView::Compositor::LocalRef(
|
|
|
|
aCls.Env(), LayerView::Compositor::Ref::From(aCompositor));
|
|
|
|
window->mLayerViewSupport.Attach(compositor, window, compositor);
|
2015-12-24 03:03:34 +00:00
|
|
|
|
Bug 1307820 - Implement per-GeckoView messaging; r=snorp r=sebastian
Bug 1307820 - 1a. Move GeckoApp EventDispatcher to GeckoView; r=snorp
Make it a GeckoView-specific EventDispatcher instead of
GeckoApp-specific, so that GeckoView consumers can benefit from a
per-view EventDispatcher. In addition, a few events like Gecko:Ready are
moved back to the global EventDispatcher because that makes more sense.
Bug 1307820 - 1b. Don't use GeckoApp EventDispatcher during inflation; r=snorp
During layout inflation, we don't yet have GeckoView and therefore the
GeckoView EventDispatcher, so we should not register events until later,
typically during onAttachedToWindow.
Bug 1307820 - 2. Introduce GeckoBundle; r=snorp
The Android Bundle class has several disadvantages when used for holding
structured data from JS.
The most obvious one is the differentiation between int and double,
which doesn't exist in JS. So when a JS number is converted to either a
Bundle int or double, we run the risk of making a wrong conversion,
resulting in a type mismatch exception when Java uses the Bundle. This
extends to number arrays from JS.
There is one more gotcha when using arrays. When we receive an empty
array from JS, there is no way for us to determine the type of the
array, because even empty arrays in Java have types. We are forced to
pick an arbitrary type like boolean[], which can easily result in a type
mismatch exception when using the array on the Java side.
In addition, Bundle is fairly cumbersome, and we cannot access the inner
structures of Bundle from Java or JNI, making it harder to use.
With these factors in mind, this patch introduces GeckoBundle as a
better choice for Gecko/Java communication. It is almost fully
API-compatible with the Android Bundle; only the Bundle array methods
are different. It resolves the numbers problem by performing conversions
if necessary, and it is a lot more lightweight than Bundle.
Bug 1307820 - 3. Convert BundleEventListener to use GeckoBundle; r=snorp
Convert BundleEventListener from using Bundle to using GeckoBundle.
Because NativeJSContainer still only supports Bundle, we do an extra
conversion when sending Bundle messages, but eventually, as we eliminate
the use of NativeJSContainer, that will go away as well.
Bug 1307820 - 4. Introduce EventDispatcher interfaces; r=snorp
Introduce several new XPCOM interfaces for the new EventDispatcher API,
these interfaces are mostly mirrored after their Java counterparts.
* nsIAndroidEventDispatcher is the main interface for
registering/unregistering listeners and for dispatching events from
JS/C++.
* nsIAndroidEventListener is the interface that JS/C++ clients implement
to receive events.
* nsIAndroidEventCallback is the interface that JS/C++ clients implement
to receive responses from dispatched events.
* nsIAndroidView is the new interface that every window receives
that is specific to the window/GeckoView pair. It is passed to chrome
scripts through window arguments.
Bug 1307820 - 5. Remove EventDispatcher references from gfx code; r=snorp
EventDispatcher was used for JPZC, but NPZC doesn't use it anymore.
Bug 1307820 - 6. General JNI template improvements; r=snorp
This patch includes several improvements to the JNI templates.
* Context::RawClassRef is removed to avoid misuse, as Context::ClassRef
should be used instead.
* Fix a compile error, in certain usages, in the DisposeNative overload
in NativeStub.
* Add Ref::IsInstanceOf and Context::IsInstanceOf to mirror the
JNIEnv::IsInstanceOf call.
* Add Ref::operator* and Context::operator* to provide an easy way to
get a Context object.
* Add built-in declarations for boxed Java objects (e.g. Boolean,
Integer, etc).
* Add ObjectArray::New for creating new object arrays of specific types.
* Add lvalue qualifiers to LocalRef::operator= and GlobalRef::operator=,
to prevent accidentally assigning to rvalues. (e.g.
`objectArray->GetElement(0) = newObject;`, which won't work as intended.)
Bug 1307820 - 7. Support ownership through RefPtr for native JNI objects; r=snorp
In addition to direct ownership and weak pointer ownership, add a third
ownership model where a native JNI object owns a RefPtr that holds a
strong reference to the actual C++ object. This ownership model works
well with ref-counted objects such as XPCOM objects, and is activated
through the presence of public members AddRef() and Release() in the C++
object.
Bug 1307820 - 8. Implement Gecko-side EventDispatcher; r=snorp
Add a skeletal implementation of EventDispatcher on the Gecko side.
Each widget::EventDispatcher will be associated with a Java
EventDispatcher, so events can be dispatched from Gecko to Java and vice
versa. AndroidBridge and nsWindow will implement
nsIAndroidEventDispatcher through widget::EventDispatcher.
Other patches will add more complete functionality such as
GeckoBundle/JSObject translation and support for callbacks.
Bug 1307820 - 9. Implement dispatching between Gecko/Java; r=snorp
Implement translation between JSObject and GeckoBundle, and use that for
dispatching events from Gecko to Java and vice versa.
Bug 1307820 - 10. Implement callback support; r=snorp
Implement callback support for both Gecko-to-Java events and
Java-to-Gecko events.
For Gecko-to-Java, we translate nsIAndroidEventCallback to a Java
EventCallback through NativeCallbackDelegate and pass it to the Java
listener.
For Java-to-Gecko, we translate EventCallback to a
nsIAndroidEventCallback through JavaCallbackDelegate and pass it to the
Gecko listener. There is another JavaCallbackDelegate on the Java side
that redirects the callback to a particular thread. For example, if the
event was dispatched from the UI thread, we make sure the callback
happens on the UI thread as well.
Bug 1307820 - 11. Add BundleEventListener support for Gecko thread; r=snorp
Add support for BundleEventListener on the Gecko thread, so that we can
use it to replace any existing GeckoEventListener or NativeEventListener
implementations that require the listener be run synchronously on the
Gecko thread.
Bug 1307820 - 12. Add global EventDispatcher in AndroidBridge; r=snorp
Add an instance of EventDispatcher to AndroidBridge to act as a global
event dispatcher.
Bug 1307820 - 13. Add per-nsWindow EventDispatcher; r=snorp
Add an instance of EventDispatcher to each nsWindow through an
AndroidView object, which implements nsIAndroidView. The nsIAndroidView
is passed to the chrome script through the window argument when opening
the window.
Bug 1307820 - 14. Update auto-generated bindings; r=me
Bug 1307820 - 15. Update testEventDispatcher; r=snorp
Update testEventDispatcher to include new functionalities in
EventDisptcher.
* Add tests for dispatching events to UI/background thread through
nsIAndroidEventDispatcher::dispatch.
* Add tests for dispatching events to UI/background thread through
EventDispatcher.dispatch.
* Add tests for dispatching events to Gecko thread through
EventDispatcher.dispatch.
Each kind of test exercises both the global EventDispatcher through
EventDispatcher.getInstance() and the per-GeckoView EventDispatcher
through GeckoApp.getEventDispatcher().
2016-11-14 13:29:50 +00:00
|
|
|
// Attach again using the new window.
|
|
|
|
androidView->mEventDispatcher->Attach(
|
|
|
|
java::EventDispatcher::Ref::From(aDispatcher), pdomWindow);
|
|
|
|
window->mAndroidView = androidView;
|
|
|
|
|
2016-02-01 22:38:14 +00:00
|
|
|
if (window->mWidgetListener) {
|
|
|
|
nsCOMPtr<nsIXULWindow> xulWindow(
|
|
|
|
window->mWidgetListener->GetXULWindow());
|
|
|
|
if (xulWindow) {
|
2016-07-21 01:43:34 +00:00
|
|
|
// Our window is not intrinsically sized, so tell nsXULWindow to
|
2016-02-01 22:38:14 +00:00
|
|
|
// not set a size for us.
|
|
|
|
xulWindow->SetIntrinsicallySized(false);
|
|
|
|
}
|
|
|
|
}
|
2015-09-21 14:13:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-12-24 03:03:34 +00:00
|
|
|
nsWindow::GeckoViewSupport::Close()
|
2015-09-21 14:13:32 +00:00
|
|
|
{
|
Bug 1307820 - Implement per-GeckoView messaging; r=snorp r=sebastian
Bug 1307820 - 1a. Move GeckoApp EventDispatcher to GeckoView; r=snorp
Make it a GeckoView-specific EventDispatcher instead of
GeckoApp-specific, so that GeckoView consumers can benefit from a
per-view EventDispatcher. In addition, a few events like Gecko:Ready are
moved back to the global EventDispatcher because that makes more sense.
Bug 1307820 - 1b. Don't use GeckoApp EventDispatcher during inflation; r=snorp
During layout inflation, we don't yet have GeckoView and therefore the
GeckoView EventDispatcher, so we should not register events until later,
typically during onAttachedToWindow.
Bug 1307820 - 2. Introduce GeckoBundle; r=snorp
The Android Bundle class has several disadvantages when used for holding
structured data from JS.
The most obvious one is the differentiation between int and double,
which doesn't exist in JS. So when a JS number is converted to either a
Bundle int or double, we run the risk of making a wrong conversion,
resulting in a type mismatch exception when Java uses the Bundle. This
extends to number arrays from JS.
There is one more gotcha when using arrays. When we receive an empty
array from JS, there is no way for us to determine the type of the
array, because even empty arrays in Java have types. We are forced to
pick an arbitrary type like boolean[], which can easily result in a type
mismatch exception when using the array on the Java side.
In addition, Bundle is fairly cumbersome, and we cannot access the inner
structures of Bundle from Java or JNI, making it harder to use.
With these factors in mind, this patch introduces GeckoBundle as a
better choice for Gecko/Java communication. It is almost fully
API-compatible with the Android Bundle; only the Bundle array methods
are different. It resolves the numbers problem by performing conversions
if necessary, and it is a lot more lightweight than Bundle.
Bug 1307820 - 3. Convert BundleEventListener to use GeckoBundle; r=snorp
Convert BundleEventListener from using Bundle to using GeckoBundle.
Because NativeJSContainer still only supports Bundle, we do an extra
conversion when sending Bundle messages, but eventually, as we eliminate
the use of NativeJSContainer, that will go away as well.
Bug 1307820 - 4. Introduce EventDispatcher interfaces; r=snorp
Introduce several new XPCOM interfaces for the new EventDispatcher API,
these interfaces are mostly mirrored after their Java counterparts.
* nsIAndroidEventDispatcher is the main interface for
registering/unregistering listeners and for dispatching events from
JS/C++.
* nsIAndroidEventListener is the interface that JS/C++ clients implement
to receive events.
* nsIAndroidEventCallback is the interface that JS/C++ clients implement
to receive responses from dispatched events.
* nsIAndroidView is the new interface that every window receives
that is specific to the window/GeckoView pair. It is passed to chrome
scripts through window arguments.
Bug 1307820 - 5. Remove EventDispatcher references from gfx code; r=snorp
EventDispatcher was used for JPZC, but NPZC doesn't use it anymore.
Bug 1307820 - 6. General JNI template improvements; r=snorp
This patch includes several improvements to the JNI templates.
* Context::RawClassRef is removed to avoid misuse, as Context::ClassRef
should be used instead.
* Fix a compile error, in certain usages, in the DisposeNative overload
in NativeStub.
* Add Ref::IsInstanceOf and Context::IsInstanceOf to mirror the
JNIEnv::IsInstanceOf call.
* Add Ref::operator* and Context::operator* to provide an easy way to
get a Context object.
* Add built-in declarations for boxed Java objects (e.g. Boolean,
Integer, etc).
* Add ObjectArray::New for creating new object arrays of specific types.
* Add lvalue qualifiers to LocalRef::operator= and GlobalRef::operator=,
to prevent accidentally assigning to rvalues. (e.g.
`objectArray->GetElement(0) = newObject;`, which won't work as intended.)
Bug 1307820 - 7. Support ownership through RefPtr for native JNI objects; r=snorp
In addition to direct ownership and weak pointer ownership, add a third
ownership model where a native JNI object owns a RefPtr that holds a
strong reference to the actual C++ object. This ownership model works
well with ref-counted objects such as XPCOM objects, and is activated
through the presence of public members AddRef() and Release() in the C++
object.
Bug 1307820 - 8. Implement Gecko-side EventDispatcher; r=snorp
Add a skeletal implementation of EventDispatcher on the Gecko side.
Each widget::EventDispatcher will be associated with a Java
EventDispatcher, so events can be dispatched from Gecko to Java and vice
versa. AndroidBridge and nsWindow will implement
nsIAndroidEventDispatcher through widget::EventDispatcher.
Other patches will add more complete functionality such as
GeckoBundle/JSObject translation and support for callbacks.
Bug 1307820 - 9. Implement dispatching between Gecko/Java; r=snorp
Implement translation between JSObject and GeckoBundle, and use that for
dispatching events from Gecko to Java and vice versa.
Bug 1307820 - 10. Implement callback support; r=snorp
Implement callback support for both Gecko-to-Java events and
Java-to-Gecko events.
For Gecko-to-Java, we translate nsIAndroidEventCallback to a Java
EventCallback through NativeCallbackDelegate and pass it to the Java
listener.
For Java-to-Gecko, we translate EventCallback to a
nsIAndroidEventCallback through JavaCallbackDelegate and pass it to the
Gecko listener. There is another JavaCallbackDelegate on the Java side
that redirects the callback to a particular thread. For example, if the
event was dispatched from the UI thread, we make sure the callback
happens on the UI thread as well.
Bug 1307820 - 11. Add BundleEventListener support for Gecko thread; r=snorp
Add support for BundleEventListener on the Gecko thread, so that we can
use it to replace any existing GeckoEventListener or NativeEventListener
implementations that require the listener be run synchronously on the
Gecko thread.
Bug 1307820 - 12. Add global EventDispatcher in AndroidBridge; r=snorp
Add an instance of EventDispatcher to AndroidBridge to act as a global
event dispatcher.
Bug 1307820 - 13. Add per-nsWindow EventDispatcher; r=snorp
Add an instance of EventDispatcher to each nsWindow through an
AndroidView object, which implements nsIAndroidView. The nsIAndroidView
is passed to the chrome script through the window argument when opening
the window.
Bug 1307820 - 14. Update auto-generated bindings; r=me
Bug 1307820 - 15. Update testEventDispatcher; r=snorp
Update testEventDispatcher to include new functionalities in
EventDisptcher.
* Add tests for dispatching events to UI/background thread through
nsIAndroidEventDispatcher::dispatch.
* Add tests for dispatching events to UI/background thread through
EventDispatcher.dispatch.
* Add tests for dispatching events to Gecko thread through
EventDispatcher.dispatch.
Each kind of test exercises both the global EventDispatcher through
EventDispatcher.getInstance() and the per-GeckoView EventDispatcher
through GeckoApp.getEventDispatcher().
2016-11-14 13:29:50 +00:00
|
|
|
if (window.mAndroidView) {
|
|
|
|
window.mAndroidView->mEventDispatcher->Detach();
|
|
|
|
}
|
|
|
|
|
2016-07-21 01:43:34 +00:00
|
|
|
if (!mDOMWindow) {
|
2015-10-22 21:45:46 +00:00
|
|
|
return;
|
2015-09-21 14:13:32 +00:00
|
|
|
}
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2016-07-21 01:43:34 +00:00
|
|
|
mDOMWindow->ForceClose();
|
|
|
|
mDOMWindow = nullptr;
|
2015-09-21 14:13:32 +00:00
|
|
|
}
|
|
|
|
|
2015-12-24 03:03:35 +00:00
|
|
|
void
|
2016-08-18 22:03:04 +00:00
|
|
|
nsWindow::GeckoViewSupport::Reattach(const GeckoView::Window::LocalRef& inst,
|
|
|
|
GeckoView::Param aView,
|
Bug 1307820 - Implement per-GeckoView messaging; r=snorp r=sebastian
Bug 1307820 - 1a. Move GeckoApp EventDispatcher to GeckoView; r=snorp
Make it a GeckoView-specific EventDispatcher instead of
GeckoApp-specific, so that GeckoView consumers can benefit from a
per-view EventDispatcher. In addition, a few events like Gecko:Ready are
moved back to the global EventDispatcher because that makes more sense.
Bug 1307820 - 1b. Don't use GeckoApp EventDispatcher during inflation; r=snorp
During layout inflation, we don't yet have GeckoView and therefore the
GeckoView EventDispatcher, so we should not register events until later,
typically during onAttachedToWindow.
Bug 1307820 - 2. Introduce GeckoBundle; r=snorp
The Android Bundle class has several disadvantages when used for holding
structured data from JS.
The most obvious one is the differentiation between int and double,
which doesn't exist in JS. So when a JS number is converted to either a
Bundle int or double, we run the risk of making a wrong conversion,
resulting in a type mismatch exception when Java uses the Bundle. This
extends to number arrays from JS.
There is one more gotcha when using arrays. When we receive an empty
array from JS, there is no way for us to determine the type of the
array, because even empty arrays in Java have types. We are forced to
pick an arbitrary type like boolean[], which can easily result in a type
mismatch exception when using the array on the Java side.
In addition, Bundle is fairly cumbersome, and we cannot access the inner
structures of Bundle from Java or JNI, making it harder to use.
With these factors in mind, this patch introduces GeckoBundle as a
better choice for Gecko/Java communication. It is almost fully
API-compatible with the Android Bundle; only the Bundle array methods
are different. It resolves the numbers problem by performing conversions
if necessary, and it is a lot more lightweight than Bundle.
Bug 1307820 - 3. Convert BundleEventListener to use GeckoBundle; r=snorp
Convert BundleEventListener from using Bundle to using GeckoBundle.
Because NativeJSContainer still only supports Bundle, we do an extra
conversion when sending Bundle messages, but eventually, as we eliminate
the use of NativeJSContainer, that will go away as well.
Bug 1307820 - 4. Introduce EventDispatcher interfaces; r=snorp
Introduce several new XPCOM interfaces for the new EventDispatcher API,
these interfaces are mostly mirrored after their Java counterparts.
* nsIAndroidEventDispatcher is the main interface for
registering/unregistering listeners and for dispatching events from
JS/C++.
* nsIAndroidEventListener is the interface that JS/C++ clients implement
to receive events.
* nsIAndroidEventCallback is the interface that JS/C++ clients implement
to receive responses from dispatched events.
* nsIAndroidView is the new interface that every window receives
that is specific to the window/GeckoView pair. It is passed to chrome
scripts through window arguments.
Bug 1307820 - 5. Remove EventDispatcher references from gfx code; r=snorp
EventDispatcher was used for JPZC, but NPZC doesn't use it anymore.
Bug 1307820 - 6. General JNI template improvements; r=snorp
This patch includes several improvements to the JNI templates.
* Context::RawClassRef is removed to avoid misuse, as Context::ClassRef
should be used instead.
* Fix a compile error, in certain usages, in the DisposeNative overload
in NativeStub.
* Add Ref::IsInstanceOf and Context::IsInstanceOf to mirror the
JNIEnv::IsInstanceOf call.
* Add Ref::operator* and Context::operator* to provide an easy way to
get a Context object.
* Add built-in declarations for boxed Java objects (e.g. Boolean,
Integer, etc).
* Add ObjectArray::New for creating new object arrays of specific types.
* Add lvalue qualifiers to LocalRef::operator= and GlobalRef::operator=,
to prevent accidentally assigning to rvalues. (e.g.
`objectArray->GetElement(0) = newObject;`, which won't work as intended.)
Bug 1307820 - 7. Support ownership through RefPtr for native JNI objects; r=snorp
In addition to direct ownership and weak pointer ownership, add a third
ownership model where a native JNI object owns a RefPtr that holds a
strong reference to the actual C++ object. This ownership model works
well with ref-counted objects such as XPCOM objects, and is activated
through the presence of public members AddRef() and Release() in the C++
object.
Bug 1307820 - 8. Implement Gecko-side EventDispatcher; r=snorp
Add a skeletal implementation of EventDispatcher on the Gecko side.
Each widget::EventDispatcher will be associated with a Java
EventDispatcher, so events can be dispatched from Gecko to Java and vice
versa. AndroidBridge and nsWindow will implement
nsIAndroidEventDispatcher through widget::EventDispatcher.
Other patches will add more complete functionality such as
GeckoBundle/JSObject translation and support for callbacks.
Bug 1307820 - 9. Implement dispatching between Gecko/Java; r=snorp
Implement translation between JSObject and GeckoBundle, and use that for
dispatching events from Gecko to Java and vice versa.
Bug 1307820 - 10. Implement callback support; r=snorp
Implement callback support for both Gecko-to-Java events and
Java-to-Gecko events.
For Gecko-to-Java, we translate nsIAndroidEventCallback to a Java
EventCallback through NativeCallbackDelegate and pass it to the Java
listener.
For Java-to-Gecko, we translate EventCallback to a
nsIAndroidEventCallback through JavaCallbackDelegate and pass it to the
Gecko listener. There is another JavaCallbackDelegate on the Java side
that redirects the callback to a particular thread. For example, if the
event was dispatched from the UI thread, we make sure the callback
happens on the UI thread as well.
Bug 1307820 - 11. Add BundleEventListener support for Gecko thread; r=snorp
Add support for BundleEventListener on the Gecko thread, so that we can
use it to replace any existing GeckoEventListener or NativeEventListener
implementations that require the listener be run synchronously on the
Gecko thread.
Bug 1307820 - 12. Add global EventDispatcher in AndroidBridge; r=snorp
Add an instance of EventDispatcher to AndroidBridge to act as a global
event dispatcher.
Bug 1307820 - 13. Add per-nsWindow EventDispatcher; r=snorp
Add an instance of EventDispatcher to each nsWindow through an
AndroidView object, which implements nsIAndroidView. The nsIAndroidView
is passed to the chrome script through the window argument when opening
the window.
Bug 1307820 - 14. Update auto-generated bindings; r=me
Bug 1307820 - 15. Update testEventDispatcher; r=snorp
Update testEventDispatcher to include new functionalities in
EventDisptcher.
* Add tests for dispatching events to UI/background thread through
nsIAndroidEventDispatcher::dispatch.
* Add tests for dispatching events to UI/background thread through
EventDispatcher.dispatch.
* Add tests for dispatching events to Gecko thread through
EventDispatcher.dispatch.
Each kind of test exercises both the global EventDispatcher through
EventDispatcher.getInstance() and the per-GeckoView EventDispatcher
through GeckoApp.getEventDispatcher().
2016-11-14 13:29:50 +00:00
|
|
|
jni::Object::Param aCompositor,
|
|
|
|
jni::Object::Param aDispatcher)
|
2015-12-24 03:03:35 +00:00
|
|
|
{
|
|
|
|
// Associate our previous GeckoEditable with the new GeckoView.
|
|
|
|
mEditable->OnViewChange(aView);
|
2016-08-01 18:21:31 +00:00
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
// mNPZCSupport might have already been detached through the Java side calling
|
|
|
|
// NativePanZoomController.destroy().
|
|
|
|
if (window.mNPZCSupport) {
|
|
|
|
window.mNPZCSupport.Detach();
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(window.mLayerViewSupport);
|
|
|
|
window.mLayerViewSupport.Detach();
|
|
|
|
|
|
|
|
auto compositor = LayerView::Compositor::LocalRef(
|
|
|
|
inst.Env(), LayerView::Compositor::Ref::From(aCompositor));
|
|
|
|
window.mLayerViewSupport.Attach(compositor, &window, compositor);
|
2016-08-23 22:55:12 +00:00
|
|
|
compositor->Reattach();
|
Bug 1307820 - Implement per-GeckoView messaging; r=snorp r=sebastian
Bug 1307820 - 1a. Move GeckoApp EventDispatcher to GeckoView; r=snorp
Make it a GeckoView-specific EventDispatcher instead of
GeckoApp-specific, so that GeckoView consumers can benefit from a
per-view EventDispatcher. In addition, a few events like Gecko:Ready are
moved back to the global EventDispatcher because that makes more sense.
Bug 1307820 - 1b. Don't use GeckoApp EventDispatcher during inflation; r=snorp
During layout inflation, we don't yet have GeckoView and therefore the
GeckoView EventDispatcher, so we should not register events until later,
typically during onAttachedToWindow.
Bug 1307820 - 2. Introduce GeckoBundle; r=snorp
The Android Bundle class has several disadvantages when used for holding
structured data from JS.
The most obvious one is the differentiation between int and double,
which doesn't exist in JS. So when a JS number is converted to either a
Bundle int or double, we run the risk of making a wrong conversion,
resulting in a type mismatch exception when Java uses the Bundle. This
extends to number arrays from JS.
There is one more gotcha when using arrays. When we receive an empty
array from JS, there is no way for us to determine the type of the
array, because even empty arrays in Java have types. We are forced to
pick an arbitrary type like boolean[], which can easily result in a type
mismatch exception when using the array on the Java side.
In addition, Bundle is fairly cumbersome, and we cannot access the inner
structures of Bundle from Java or JNI, making it harder to use.
With these factors in mind, this patch introduces GeckoBundle as a
better choice for Gecko/Java communication. It is almost fully
API-compatible with the Android Bundle; only the Bundle array methods
are different. It resolves the numbers problem by performing conversions
if necessary, and it is a lot more lightweight than Bundle.
Bug 1307820 - 3. Convert BundleEventListener to use GeckoBundle; r=snorp
Convert BundleEventListener from using Bundle to using GeckoBundle.
Because NativeJSContainer still only supports Bundle, we do an extra
conversion when sending Bundle messages, but eventually, as we eliminate
the use of NativeJSContainer, that will go away as well.
Bug 1307820 - 4. Introduce EventDispatcher interfaces; r=snorp
Introduce several new XPCOM interfaces for the new EventDispatcher API,
these interfaces are mostly mirrored after their Java counterparts.
* nsIAndroidEventDispatcher is the main interface for
registering/unregistering listeners and for dispatching events from
JS/C++.
* nsIAndroidEventListener is the interface that JS/C++ clients implement
to receive events.
* nsIAndroidEventCallback is the interface that JS/C++ clients implement
to receive responses from dispatched events.
* nsIAndroidView is the new interface that every window receives
that is specific to the window/GeckoView pair. It is passed to chrome
scripts through window arguments.
Bug 1307820 - 5. Remove EventDispatcher references from gfx code; r=snorp
EventDispatcher was used for JPZC, but NPZC doesn't use it anymore.
Bug 1307820 - 6. General JNI template improvements; r=snorp
This patch includes several improvements to the JNI templates.
* Context::RawClassRef is removed to avoid misuse, as Context::ClassRef
should be used instead.
* Fix a compile error, in certain usages, in the DisposeNative overload
in NativeStub.
* Add Ref::IsInstanceOf and Context::IsInstanceOf to mirror the
JNIEnv::IsInstanceOf call.
* Add Ref::operator* and Context::operator* to provide an easy way to
get a Context object.
* Add built-in declarations for boxed Java objects (e.g. Boolean,
Integer, etc).
* Add ObjectArray::New for creating new object arrays of specific types.
* Add lvalue qualifiers to LocalRef::operator= and GlobalRef::operator=,
to prevent accidentally assigning to rvalues. (e.g.
`objectArray->GetElement(0) = newObject;`, which won't work as intended.)
Bug 1307820 - 7. Support ownership through RefPtr for native JNI objects; r=snorp
In addition to direct ownership and weak pointer ownership, add a third
ownership model where a native JNI object owns a RefPtr that holds a
strong reference to the actual C++ object. This ownership model works
well with ref-counted objects such as XPCOM objects, and is activated
through the presence of public members AddRef() and Release() in the C++
object.
Bug 1307820 - 8. Implement Gecko-side EventDispatcher; r=snorp
Add a skeletal implementation of EventDispatcher on the Gecko side.
Each widget::EventDispatcher will be associated with a Java
EventDispatcher, so events can be dispatched from Gecko to Java and vice
versa. AndroidBridge and nsWindow will implement
nsIAndroidEventDispatcher through widget::EventDispatcher.
Other patches will add more complete functionality such as
GeckoBundle/JSObject translation and support for callbacks.
Bug 1307820 - 9. Implement dispatching between Gecko/Java; r=snorp
Implement translation between JSObject and GeckoBundle, and use that for
dispatching events from Gecko to Java and vice versa.
Bug 1307820 - 10. Implement callback support; r=snorp
Implement callback support for both Gecko-to-Java events and
Java-to-Gecko events.
For Gecko-to-Java, we translate nsIAndroidEventCallback to a Java
EventCallback through NativeCallbackDelegate and pass it to the Java
listener.
For Java-to-Gecko, we translate EventCallback to a
nsIAndroidEventCallback through JavaCallbackDelegate and pass it to the
Gecko listener. There is another JavaCallbackDelegate on the Java side
that redirects the callback to a particular thread. For example, if the
event was dispatched from the UI thread, we make sure the callback
happens on the UI thread as well.
Bug 1307820 - 11. Add BundleEventListener support for Gecko thread; r=snorp
Add support for BundleEventListener on the Gecko thread, so that we can
use it to replace any existing GeckoEventListener or NativeEventListener
implementations that require the listener be run synchronously on the
Gecko thread.
Bug 1307820 - 12. Add global EventDispatcher in AndroidBridge; r=snorp
Add an instance of EventDispatcher to AndroidBridge to act as a global
event dispatcher.
Bug 1307820 - 13. Add per-nsWindow EventDispatcher; r=snorp
Add an instance of EventDispatcher to each nsWindow through an
AndroidView object, which implements nsIAndroidView. The nsIAndroidView
is passed to the chrome script through the window argument when opening
the window.
Bug 1307820 - 14. Update auto-generated bindings; r=me
Bug 1307820 - 15. Update testEventDispatcher; r=snorp
Update testEventDispatcher to include new functionalities in
EventDisptcher.
* Add tests for dispatching events to UI/background thread through
nsIAndroidEventDispatcher::dispatch.
* Add tests for dispatching events to UI/background thread through
EventDispatcher.dispatch.
* Add tests for dispatching events to Gecko thread through
EventDispatcher.dispatch.
Each kind of test exercises both the global EventDispatcher through
EventDispatcher.getInstance() and the per-GeckoView EventDispatcher
through GeckoApp.getEventDispatcher().
2016-11-14 13:29:50 +00:00
|
|
|
|
|
|
|
MOZ_ASSERT(window.mAndroidView);
|
|
|
|
window.mAndroidView->mEventDispatcher->Attach(
|
|
|
|
java::EventDispatcher::Ref::From(aDispatcher), mDOMWindow);
|
2015-12-24 03:03:35 +00:00
|
|
|
}
|
|
|
|
|
2016-07-21 01:43:34 +00:00
|
|
|
void
|
|
|
|
nsWindow::GeckoViewSupport::LoadUri(jni::String::Param aUri, int32_t aFlags)
|
|
|
|
{
|
|
|
|
if (!mDOMWindow) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> uri = nsAppShell::ResolveURI(aUri->ToCString());
|
|
|
|
if (NS_WARN_IF(!uri)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMChromeWindow> chromeWin = do_QueryInterface(mDOMWindow);
|
|
|
|
nsCOMPtr<nsIBrowserDOMWindow> browserWin;
|
|
|
|
|
|
|
|
if (NS_WARN_IF(!chromeWin) || NS_WARN_IF(NS_FAILED(
|
|
|
|
chromeWin->GetBrowserDOMWindow(getter_AddRefs(browserWin))))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const int flags = aFlags == GeckoView::LOAD_NEW_TAB ?
|
|
|
|
nsIBrowserDOMWindow::OPEN_NEWTAB :
|
|
|
|
aFlags == GeckoView::LOAD_SWITCH_TAB ?
|
|
|
|
nsIBrowserDOMWindow::OPEN_SWITCHTAB :
|
|
|
|
nsIBrowserDOMWindow::OPEN_CURRENTWINDOW;
|
|
|
|
nsCOMPtr<mozIDOMWindowProxy> newWin;
|
|
|
|
|
|
|
|
if (NS_FAILED(browserWin->OpenURI(
|
|
|
|
uri, nullptr, flags, nsIBrowserDOMWindow::OPEN_EXTERNAL,
|
|
|
|
getter_AddRefs(newWin)))) {
|
|
|
|
NS_WARNING("Failed to open URI");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-21 14:13:32 +00:00
|
|
|
void
|
|
|
|
nsWindow::InitNatives()
|
|
|
|
{
|
2015-12-24 03:03:34 +00:00
|
|
|
nsWindow::GeckoViewSupport::Base::Init();
|
|
|
|
nsWindow::GeckoViewSupport::EditableBase::Init();
|
2016-08-01 18:21:31 +00:00
|
|
|
nsWindow::LayerViewSupport::Init();
|
2016-01-15 18:05:45 +00:00
|
|
|
nsWindow::NPZCSupport::Init();
|
2016-09-29 03:49:25 +00:00
|
|
|
if (jni::IsFennec()) {
|
|
|
|
nsWindow::PMPMSupport::Init();
|
|
|
|
}
|
2015-09-21 14:13:32 +00:00
|
|
|
}
|
|
|
|
|
2012-04-20 16:49:50 +00:00
|
|
|
nsWindow*
|
|
|
|
nsWindow::TopWindow()
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
|
|
|
if (!gTopLevelWindows.IsEmpty())
|
|
|
|
return gTopLevelWindows[0];
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::LogWindow(nsWindow *win, int index, int indent)
|
|
|
|
{
|
2013-01-25 19:33:40 +00:00
|
|
|
#if defined(DEBUG) || defined(FORCE_ALOG)
|
2010-06-03 20:56:36 +00:00
|
|
|
char spaces[] = " ";
|
|
|
|
spaces[indent < 20 ? indent : 20] = 0;
|
2012-05-26 15:07:24 +00:00
|
|
|
ALOG("%s [% 2d] 0x%08x [parent 0x%08x] [% 3d,% 3dx% 3d,% 3d] vis %d type %d",
|
2010-06-03 20:56:36 +00:00
|
|
|
spaces, index, (intptr_t)win, (intptr_t)win->mParent,
|
|
|
|
win->mBounds.x, win->mBounds.y,
|
|
|
|
win->mBounds.width, win->mBounds.height,
|
|
|
|
win->mIsVisible, win->mWindowType);
|
2013-01-25 19:33:40 +00:00
|
|
|
#endif
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::DumpWindows()
|
|
|
|
{
|
|
|
|
DumpWindows(gTopLevelWindows);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::DumpWindows(const nsTArray<nsWindow*>& wins, int indent)
|
|
|
|
{
|
2012-08-22 15:56:38 +00:00
|
|
|
for (uint32_t i = 0; i < wins.Length(); ++i) {
|
2010-06-03 20:56:36 +00:00
|
|
|
nsWindow *w = wins[i];
|
|
|
|
LogWindow(w, i, indent);
|
|
|
|
DumpWindows(w->mChildren, indent+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsWindow::nsWindow() :
|
2016-09-29 06:23:56 +00:00
|
|
|
mScreenId(0), // Use 0 (primary screen) as the default value.
|
2011-10-17 14:59:28 +00:00
|
|
|
mIsVisible(false),
|
2012-07-30 14:20:58 +00:00
|
|
|
mParent(nullptr),
|
2015-07-02 20:00:44 +00:00
|
|
|
mAwaitingFullScreen(false),
|
|
|
|
mIsFullScreen(false)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsWindow::~nsWindow()
|
|
|
|
{
|
|
|
|
gTopLevelWindows.RemoveElement(this);
|
|
|
|
ALOG("nsWindow %p destructor", (void*)this);
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2010-06-03 20:56:36 +00:00
|
|
|
nsWindow::IsTopLevel()
|
|
|
|
{
|
|
|
|
return mWindowType == eWindowType_toplevel ||
|
|
|
|
mWindowType == eWindowType_dialog ||
|
|
|
|
mWindowType == eWindowType_invisible;
|
|
|
|
}
|
|
|
|
|
2016-08-18 23:03:17 +00:00
|
|
|
nsresult
|
2015-11-16 08:35:18 +00:00
|
|
|
nsWindow::Create(nsIWidget* aParent,
|
2010-06-03 20:56:36 +00:00
|
|
|
nsNativeWidget aNativeParent,
|
2015-11-16 08:35:18 +00:00
|
|
|
const LayoutDeviceIntRect& aRect,
|
|
|
|
nsWidgetInitData* aInitData)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2016-02-01 22:38:14 +00:00
|
|
|
ALOG("nsWindow[%p]::Create %p [%d %d %d %d]", (void*)this, (void*)aParent,
|
|
|
|
aRect.x, aRect.y, aRect.width, aRect.height);
|
|
|
|
|
2010-06-03 20:56:36 +00:00
|
|
|
nsWindow *parent = (nsWindow*) aParent;
|
|
|
|
if (aNativeParent) {
|
|
|
|
if (parent) {
|
2016-02-01 22:38:14 +00:00
|
|
|
ALOG("Ignoring native parent on Android window [%p], "
|
|
|
|
"since parent was specified (%p %p)", (void*)this,
|
|
|
|
(void*)aNativeParent, (void*)aParent);
|
2010-06-03 20:56:36 +00:00
|
|
|
} else {
|
|
|
|
parent = (nsWindow*) aNativeParent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-23 04:32:29 +00:00
|
|
|
mBounds = aRect;
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2016-01-13 07:32:55 +00:00
|
|
|
BaseCreate(nullptr, aInitData);
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2016-02-01 22:38:14 +00:00
|
|
|
NS_ASSERTION(IsTopLevel() || parent,
|
|
|
|
"non-top-level window doesn't have a parent!");
|
2010-06-03 20:56:36 +00:00
|
|
|
|
|
|
|
if (IsTopLevel()) {
|
|
|
|
gTopLevelWindows.AppendElement(this);
|
|
|
|
|
2016-02-01 22:38:14 +00:00
|
|
|
} else if (parent) {
|
2010-06-03 20:56:36 +00:00
|
|
|
parent->mChildren.AppendElement(this);
|
|
|
|
mParent = parent;
|
|
|
|
}
|
|
|
|
|
2012-12-21 16:33:28 +00:00
|
|
|
#ifdef DEBUG_ANDROID_WIDGET
|
|
|
|
DumpWindows();
|
|
|
|
#endif
|
|
|
|
|
2010-06-03 20:56:36 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-08-10 00:04:11 +00:00
|
|
|
void
|
|
|
|
nsWindow::Destroy()
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2011-11-22 20:31:49 +00:00
|
|
|
nsBaseWidget::mOnDestroyCalled = true;
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
if (mGeckoViewSupport) {
|
2015-10-22 21:45:46 +00:00
|
|
|
// Disassociate our native object with GeckoView.
|
2015-12-24 03:03:34 +00:00
|
|
|
mGeckoViewSupport = nullptr;
|
2015-10-22 21:45:46 +00:00
|
|
|
}
|
|
|
|
|
2016-04-21 19:07:01 +00:00
|
|
|
// Stuff below may release the last ref to this
|
|
|
|
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
|
|
|
|
|
2012-05-26 15:06:25 +00:00
|
|
|
while (mChildren.Length()) {
|
2010-06-03 20:56:36 +00:00
|
|
|
// why do we still have children?
|
2012-05-26 15:06:25 +00:00
|
|
|
ALOG("### Warning: Destroying window %p and reparenting child %p to null!", (void*)this, (void*)mChildren[0]);
|
2012-07-30 14:20:58 +00:00
|
|
|
mChildren[0]->SetParent(nullptr);
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2016-04-21 19:07:01 +00:00
|
|
|
nsBaseWidget::Destroy();
|
|
|
|
|
2010-06-03 20:56:36 +00:00
|
|
|
if (IsTopLevel())
|
|
|
|
gTopLevelWindows.RemoveElement(this);
|
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
SetParent(nullptr);
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2011-11-22 20:29:54 +00:00
|
|
|
nsBaseWidget::OnDestroy();
|
|
|
|
|
2012-12-21 16:33:28 +00:00
|
|
|
#ifdef DEBUG_ANDROID_WIDGET
|
|
|
|
DumpWindows();
|
|
|
|
#endif
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2016-12-21 04:58:09 +00:00
|
|
|
nsresult
|
2010-06-03 20:56:36 +00:00
|
|
|
nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>& config)
|
|
|
|
{
|
2012-08-22 15:56:38 +00:00
|
|
|
for (uint32_t i = 0; i < config.Length(); ++i) {
|
2015-05-25 18:45:00 +00:00
|
|
|
nsWindow *childWin = (nsWindow*) config[i].mChild.get();
|
2010-06-03 20:56:36 +00:00
|
|
|
childWin->Resize(config[i].mBounds.x,
|
|
|
|
config[i].mBounds.y,
|
|
|
|
config[i].mBounds.width,
|
|
|
|
config[i].mBounds.height,
|
2011-10-17 14:59:28 +00:00
|
|
|
false);
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-11-10 01:39:29 +00:00
|
|
|
void
|
|
|
|
nsWindow::RedrawAll()
|
|
|
|
{
|
2015-04-25 02:26:34 +00:00
|
|
|
if (mAttachedWidgetListener) {
|
|
|
|
mAttachedWidgetListener->RequestRepaint();
|
|
|
|
} else if (mWidgetListener) {
|
2015-04-17 16:29:51 +00:00
|
|
|
mWidgetListener->RequestRepaint();
|
2012-09-04 22:06:22 +00:00
|
|
|
}
|
2011-11-10 01:39:29 +00:00
|
|
|
}
|
|
|
|
|
2017-01-05 19:11:41 +00:00
|
|
|
int64_t
|
|
|
|
nsWindow::GetRootLayerId() const
|
|
|
|
{
|
|
|
|
return mCompositorSession ? mCompositorSession->RootLayerTreeId() : 0;
|
|
|
|
}
|
|
|
|
|
2016-12-15 23:54:11 +00:00
|
|
|
void
|
2010-06-03 20:56:36 +00:00
|
|
|
nsWindow::SetParent(nsIWidget *aNewParent)
|
|
|
|
{
|
|
|
|
if ((nsIWidget*)mParent == aNewParent)
|
2016-12-15 23:54:11 +00:00
|
|
|
return;
|
2010-06-03 20:56:36 +00:00
|
|
|
|
|
|
|
// If we had a parent before, remove ourselves from its list of
|
2012-05-26 15:07:24 +00:00
|
|
|
// children.
|
2010-06-03 20:56:36 +00:00
|
|
|
if (mParent)
|
|
|
|
mParent->mChildren.RemoveElement(this);
|
|
|
|
|
|
|
|
mParent = (nsWindow*)aNewParent;
|
|
|
|
|
|
|
|
if (mParent)
|
|
|
|
mParent->mChildren.AppendElement(this);
|
|
|
|
|
|
|
|
// if we are now in the toplevel window's hierarchy, schedule a redraw
|
2012-04-20 16:49:50 +00:00
|
|
|
if (FindTopLevel() == nsWindow::TopWindow())
|
2011-11-10 01:39:29 +00:00
|
|
|
RedrawAll();
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsIWidget*
|
|
|
|
nsWindow::GetParent()
|
|
|
|
{
|
|
|
|
return mParent;
|
|
|
|
}
|
|
|
|
|
2010-10-07 17:28:27 +00:00
|
|
|
float
|
|
|
|
nsWindow::GetDPI()
|
|
|
|
{
|
|
|
|
if (AndroidBridge::Bridge())
|
|
|
|
return AndroidBridge::Bridge()->GetDPI();
|
|
|
|
return 160.0f;
|
|
|
|
}
|
|
|
|
|
2013-07-04 13:02:29 +00:00
|
|
|
double
|
|
|
|
nsWindow::GetDefaultScaleInternal()
|
|
|
|
{
|
2013-09-18 00:45:03 +00:00
|
|
|
|
2016-09-29 06:23:56 +00:00
|
|
|
nsCOMPtr<nsIScreen> screen = GetWidgetScreen();
|
|
|
|
MOZ_ASSERT(screen);
|
|
|
|
RefPtr<nsScreenAndroid> screenAndroid = (nsScreenAndroid*) screen.get();
|
|
|
|
return screenAndroid->GetDensity();
|
2013-07-04 13:02:29 +00:00
|
|
|
}
|
|
|
|
|
2016-12-21 00:12:54 +00:00
|
|
|
void
|
2011-09-29 06:19:26 +00:00
|
|
|
nsWindow::Show(bool aState)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
|
|
|
ALOG("nsWindow[%p]::Show %d", (void*)this, aState);
|
|
|
|
|
|
|
|
if (mWindowType == eWindowType_invisible) {
|
|
|
|
ALOG("trying to show invisible window! ignoring..");
|
2016-12-21 00:12:54 +00:00
|
|
|
return;
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2011-02-15 01:01:01 +00:00
|
|
|
if (aState == mIsVisible)
|
2016-12-21 00:12:54 +00:00
|
|
|
return;
|
2011-02-15 01:01:01 +00:00
|
|
|
|
|
|
|
mIsVisible = aState;
|
|
|
|
|
|
|
|
if (IsTopLevel()) {
|
|
|
|
// XXX should we bring this to the front when it's shown,
|
|
|
|
// if it's a toplevel widget?
|
|
|
|
|
2015-08-28 23:58:31 +00:00
|
|
|
// XXX we should synthesize a eMouseExitFromWidget (for old top
|
2015-08-28 23:58:31 +00:00
|
|
|
// window)/eMouseEnterIntoWidget (for new top window) since we need
|
2011-02-15 01:01:01 +00:00
|
|
|
// to pretend that the top window always has focus. Not sure
|
|
|
|
// if Show() is the right place to do this, though.
|
|
|
|
|
|
|
|
if (aState) {
|
2016-02-01 22:38:14 +00:00
|
|
|
// It just became visible, so bring it to the front.
|
2011-02-15 01:01:01 +00:00
|
|
|
BringToFront();
|
2016-02-01 22:38:14 +00:00
|
|
|
|
2012-04-20 16:49:50 +00:00
|
|
|
} else if (nsWindow::TopWindow() == this) {
|
2011-02-15 01:01:01 +00:00
|
|
|
// find the next visible window to show
|
2011-03-02 17:23:02 +00:00
|
|
|
unsigned int i;
|
2011-02-15 01:01:01 +00:00
|
|
|
for (i = 1; i < gTopLevelWindows.Length(); i++) {
|
|
|
|
nsWindow *win = gTopLevelWindows[i];
|
|
|
|
if (!win->mIsVisible)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
win->BringToFront();
|
|
|
|
break;
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
}
|
2012-04-20 16:49:50 +00:00
|
|
|
} else if (FindTopLevel() == nsWindow::TopWindow()) {
|
2011-11-10 01:39:29 +00:00
|
|
|
RedrawAll();
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2011-08-29 18:29:39 +00:00
|
|
|
#ifdef DEBUG_ANDROID_WIDGET
|
2010-06-03 20:56:36 +00:00
|
|
|
DumpWindows();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-07-19 08:57:50 +00:00
|
|
|
bool
|
|
|
|
nsWindow::IsVisible() const
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2012-07-19 08:57:50 +00:00
|
|
|
return mIsVisible;
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2016-08-25 03:43:27 +00:00
|
|
|
void
|
2011-09-29 06:19:26 +00:00
|
|
|
nsWindow::ConstrainPosition(bool aAllowSlop,
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t *aX,
|
|
|
|
int32_t *aY)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
|
|
|
ALOG("nsWindow[%p]::ConstrainPosition %d [%d %d]", (void*)this, aAllowSlop, *aX, *aY);
|
|
|
|
|
|
|
|
// constrain toplevel windows; children we don't care about
|
|
|
|
if (IsTopLevel()) {
|
|
|
|
*aX = 0;
|
|
|
|
*aY = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-19 09:54:03 +00:00
|
|
|
void
|
2012-12-12 09:57:38 +00:00
|
|
|
nsWindow::Move(double aX,
|
|
|
|
double aY)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
|
|
|
if (IsTopLevel())
|
2016-12-19 09:54:03 +00:00
|
|
|
return;
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2016-12-19 09:54:03 +00:00
|
|
|
Resize(aX,
|
|
|
|
aY,
|
|
|
|
mBounds.width,
|
|
|
|
mBounds.height,
|
|
|
|
true);
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2016-12-19 09:54:03 +00:00
|
|
|
void
|
2012-12-12 09:57:38 +00:00
|
|
|
nsWindow::Resize(double aWidth,
|
|
|
|
double aHeight,
|
2011-09-29 06:19:26 +00:00
|
|
|
bool aRepaint)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2016-12-19 09:54:03 +00:00
|
|
|
Resize(mBounds.x,
|
|
|
|
mBounds.y,
|
|
|
|
aWidth,
|
|
|
|
aHeight,
|
|
|
|
aRepaint);
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2016-12-19 09:54:03 +00:00
|
|
|
void
|
2012-12-12 09:57:38 +00:00
|
|
|
nsWindow::Resize(double aX,
|
|
|
|
double aY,
|
|
|
|
double aWidth,
|
|
|
|
double aHeight,
|
2011-09-29 06:19:26 +00:00
|
|
|
bool aRepaint)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2012-12-12 09:57:38 +00:00
|
|
|
ALOG("nsWindow[%p]::Resize [%f %f %f %f] (repaint %d)", (void*)this, aX, aY, aWidth, aHeight, aRepaint);
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool needSizeDispatch = aWidth != mBounds.width || aHeight != mBounds.height;
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2012-12-12 09:57:38 +00:00
|
|
|
mBounds.x = NSToIntRound(aX);
|
|
|
|
mBounds.y = NSToIntRound(aY);
|
|
|
|
mBounds.width = NSToIntRound(aWidth);
|
|
|
|
mBounds.height = NSToIntRound(aHeight);
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2016-07-26 14:48:30 +00:00
|
|
|
if (needSizeDispatch) {
|
|
|
|
OnSizeChanged(gfx::IntSize::Truncate(aWidth, aHeight));
|
|
|
|
}
|
2010-06-03 20:56:36 +00:00
|
|
|
|
|
|
|
// Should we skip honoring aRepaint here?
|
2012-04-20 16:49:50 +00:00
|
|
|
if (aRepaint && FindTopLevel() == nsWindow::TopWindow())
|
2011-11-10 01:39:29 +00:00
|
|
|
RedrawAll();
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2015-07-02 20:00:44 +00:00
|
|
|
nsIWidgetListener* listener = GetWidgetListener();
|
|
|
|
if (mAwaitingFullScreen && listener) {
|
2016-12-19 09:54:03 +00:00
|
|
|
listener->FullscreenChanged(mIsFullScreen);
|
|
|
|
mAwaitingFullScreen = false;
|
2015-07-02 20:00:44 +00:00
|
|
|
}
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2014-03-19 16:48:08 +00:00
|
|
|
void
|
2012-08-22 15:56:38 +00:00
|
|
|
nsWindow::SetZIndex(int32_t aZIndex)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
|
|
|
ALOG("nsWindow[%p]::SetZIndex %d ignored", (void*)this, aZIndex);
|
|
|
|
}
|
|
|
|
|
2016-08-21 23:15:49 +00:00
|
|
|
void
|
2015-08-29 01:12:41 +00:00
|
|
|
nsWindow::SetSizeMode(nsSizeMode aMode)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2010-06-16 17:20:54 +00:00
|
|
|
switch (aMode) {
|
|
|
|
case nsSizeMode_Minimized:
|
2015-01-10 00:33:57 +00:00
|
|
|
GeckoAppShell::MoveTaskToBack();
|
2010-06-16 17:20:54 +00:00
|
|
|
break;
|
2010-11-09 02:11:13 +00:00
|
|
|
case nsSizeMode_Fullscreen:
|
2011-10-17 14:59:28 +00:00
|
|
|
MakeFullScreen(true);
|
2010-11-09 02:11:13 +00:00
|
|
|
break;
|
2015-08-29 01:43:28 +00:00
|
|
|
default:
|
2015-08-29 02:30:32 +00:00
|
|
|
break;
|
2010-06-16 17:20:54 +00:00
|
|
|
}
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2016-12-19 09:54:16 +00:00
|
|
|
void
|
2011-09-29 06:19:26 +00:00
|
|
|
nsWindow::Enable(bool aState)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
|
|
|
ALOG("nsWindow[%p]::Enable %d ignored", (void*)this, aState);
|
|
|
|
}
|
|
|
|
|
2012-07-23 05:19:08 +00:00
|
|
|
bool
|
|
|
|
nsWindow::IsEnabled() const
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2012-07-23 05:19:08 +00:00
|
|
|
return true;
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2016-12-19 22:55:32 +00:00
|
|
|
void
|
2015-11-17 05:18:31 +00:00
|
|
|
nsWindow::Invalidate(const LayoutDeviceIntRect& aRect)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsWindow*
|
|
|
|
nsWindow::FindTopLevel()
|
|
|
|
{
|
|
|
|
nsWindow *toplevel = this;
|
|
|
|
while (toplevel) {
|
|
|
|
if (toplevel->IsTopLevel())
|
|
|
|
return toplevel;
|
|
|
|
|
|
|
|
toplevel = toplevel->mParent;
|
|
|
|
}
|
|
|
|
|
|
|
|
ALOG("nsWindow::FindTopLevel(): couldn't find a toplevel or dialog window in this [%p] widget's hierarchy!", (void*)this);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2016-12-21 00:13:08 +00:00
|
|
|
nsresult
|
2011-09-29 06:19:26 +00:00
|
|
|
nsWindow::SetFocus(bool aRaise)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2011-02-15 01:01:01 +00:00
|
|
|
nsWindow *top = FindTopLevel();
|
|
|
|
top->BringToFront();
|
2010-06-03 20:56:36 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::BringToFront()
|
|
|
|
{
|
2011-11-08 19:58:37 +00:00
|
|
|
// If the window to be raised is the same as the currently raised one,
|
|
|
|
// do nothing. We need to check the focus manager as well, as the first
|
|
|
|
// window that is created will be first in the window list but won't yet
|
|
|
|
// be focused.
|
|
|
|
nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
|
2016-01-30 17:05:36 +00:00
|
|
|
nsCOMPtr<mozIDOMWindowProxy> existingTopWindow;
|
2011-11-08 19:58:37 +00:00
|
|
|
fm->GetActiveWindow(getter_AddRefs(existingTopWindow));
|
2012-04-20 16:49:50 +00:00
|
|
|
if (existingTopWindow && FindTopLevel() == nsWindow::TopWindow())
|
2010-06-03 20:56:36 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (!IsTopLevel()) {
|
|
|
|
FindTopLevel()->BringToFront();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-18 05:24:48 +00:00
|
|
|
RefPtr<nsWindow> kungFuDeathGrip(this);
|
2011-11-22 20:31:49 +00:00
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
nsWindow *oldTop = nullptr;
|
2016-02-01 22:38:14 +00:00
|
|
|
if (!gTopLevelWindows.IsEmpty()) {
|
2010-06-03 20:56:36 +00:00
|
|
|
oldTop = gTopLevelWindows[0];
|
2016-02-01 22:38:14 +00:00
|
|
|
}
|
2010-06-03 20:56:36 +00:00
|
|
|
|
|
|
|
gTopLevelWindows.RemoveElement(this);
|
|
|
|
gTopLevelWindows.InsertElementAt(0, this);
|
|
|
|
|
|
|
|
if (oldTop) {
|
2012-08-15 18:52:42 +00:00
|
|
|
nsIWidgetListener* listener = oldTop->GetWidgetListener();
|
|
|
|
if (listener) {
|
|
|
|
listener->WindowDeactivated();
|
|
|
|
}
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2012-08-15 18:52:42 +00:00
|
|
|
if (mWidgetListener) {
|
|
|
|
mWidgetListener->WindowActivated();
|
|
|
|
}
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2011-11-10 01:39:29 +00:00
|
|
|
RedrawAll();
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2016-08-18 23:03:04 +00:00
|
|
|
LayoutDeviceIntRect
|
|
|
|
nsWindow::GetScreenBounds()
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2016-08-18 23:03:04 +00:00
|
|
|
return LayoutDeviceIntRect(WidgetToScreenOffset(), mBounds.Size());
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2015-02-04 20:21:03 +00:00
|
|
|
LayoutDeviceIntPoint
|
2010-06-03 20:56:36 +00:00
|
|
|
nsWindow::WidgetToScreenOffset()
|
|
|
|
{
|
2015-02-04 20:21:03 +00:00
|
|
|
LayoutDeviceIntPoint p(0, 0);
|
2010-06-03 20:56:36 +00:00
|
|
|
nsWindow *w = this;
|
|
|
|
|
|
|
|
while (w && !w->IsTopLevel()) {
|
|
|
|
p.x += w->mBounds.x;
|
|
|
|
p.y += w->mBounds.y;
|
|
|
|
|
|
|
|
w = w->mParent;
|
|
|
|
}
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2016-12-21 00:18:40 +00:00
|
|
|
nsresult
|
2013-10-02 03:46:03 +00:00
|
|
|
nsWindow::DispatchEvent(WidgetGUIEvent* aEvent,
|
2015-04-17 16:29:51 +00:00
|
|
|
nsEventStatus& aStatus)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
|
|
|
aStatus = DispatchEvent(aEvent);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsEventStatus
|
2013-10-02 03:46:03 +00:00
|
|
|
nsWindow::DispatchEvent(WidgetGUIEvent* aEvent)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2015-04-25 02:26:34 +00:00
|
|
|
if (mAttachedWidgetListener) {
|
|
|
|
return mAttachedWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
|
|
|
|
} else if (mWidgetListener) {
|
2015-03-31 22:20:27 +00:00
|
|
|
return mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
|
2010-08-21 00:07:26 +00:00
|
|
|
}
|
2010-06-03 20:56:36 +00:00
|
|
|
return nsEventStatus_eIgnore;
|
|
|
|
}
|
|
|
|
|
2016-08-18 23:27:28 +00:00
|
|
|
nsresult
|
2014-07-09 19:29:28 +00:00
|
|
|
nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen*)
|
2010-11-09 02:11:13 +00:00
|
|
|
{
|
2015-07-02 20:00:44 +00:00
|
|
|
mIsFullScreen = aFullScreen;
|
|
|
|
mAwaitingFullScreen = true;
|
2015-01-10 00:33:57 +00:00
|
|
|
GeckoAppShell::SetFullScreen(aFullScreen);
|
2010-11-09 02:11:13 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-09-08 22:19:11 +00:00
|
|
|
mozilla::layers::LayerManager*
|
2016-06-24 00:53:27 +00:00
|
|
|
nsWindow::GetLayerManager(PLayerTransactionChild*, LayersBackend, LayerManagerPersistence)
|
2010-09-08 22:19:11 +00:00
|
|
|
{
|
|
|
|
if (mLayerManager) {
|
|
|
|
return mLayerManager;
|
|
|
|
}
|
2013-02-28 18:28:23 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-03-20 22:45:07 +00:00
|
|
|
nsWindow::CreateLayerManager(int aCompositorWidth, int aCompositorHeight)
|
2013-02-28 18:28:23 +00:00
|
|
|
{
|
|
|
|
if (mLayerManager) {
|
|
|
|
return;
|
|
|
|
}
|
2010-09-08 22:19:11 +00:00
|
|
|
|
2012-12-21 16:33:28 +00:00
|
|
|
nsWindow *topLevelWindow = FindTopLevel();
|
|
|
|
if (!topLevelWindow || topLevelWindow->mWindowType == eWindowType_invisible) {
|
|
|
|
// don't create a layer manager for an invisible top-level window
|
2013-02-28 18:28:23 +00:00
|
|
|
return;
|
2010-09-08 22:19:11 +00:00
|
|
|
}
|
2012-06-13 19:54:02 +00:00
|
|
|
|
2016-04-29 04:52:54 +00:00
|
|
|
// Ensure that gfxPlatform is initialized first.
|
|
|
|
gfxPlatform::GetPlatform();
|
|
|
|
|
2013-03-04 18:32:20 +00:00
|
|
|
if (ShouldUseOffMainThreadCompositing()) {
|
2013-03-20 22:45:07 +00:00
|
|
|
CreateCompositor(aCompositorWidth, aCompositorHeight);
|
2012-02-04 02:35:58 +00:00
|
|
|
if (mLayerManager) {
|
2013-02-28 18:28:23 +00:00
|
|
|
return;
|
2012-02-04 02:35:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we get here, then off main thread compositing failed to initialize.
|
2012-02-02 19:16:59 +00:00
|
|
|
sFailedToCreateGLContext = true;
|
2012-02-01 19:15:52 +00:00
|
|
|
}
|
2010-09-08 22:19:11 +00:00
|
|
|
|
2015-07-16 22:18:05 +00:00
|
|
|
if (!ComputeShouldAccelerate() || sFailedToCreateGLContext) {
|
2010-09-08 22:19:11 +00:00
|
|
|
printf_stderr(" -- creating basic, not accelerated\n");
|
2010-09-14 23:40:23 +00:00
|
|
|
mLayerManager = CreateBasicLayerManager();
|
2010-09-08 22:19:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-03 20:56:36 +00:00
|
|
|
void
|
2015-09-23 18:49:05 +00:00
|
|
|
nsWindow::OnSizeChanged(const gfx::IntSize& aSize)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2012-08-15 18:52:42 +00:00
|
|
|
ALOG("nsWindow: %p OnSizeChanged [%d %d]", (void*)this, aSize.width, aSize.height);
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2012-08-15 18:52:42 +00:00
|
|
|
mBounds.width = aSize.width;
|
|
|
|
mBounds.height = aSize.height;
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2012-08-15 18:52:42 +00:00
|
|
|
if (mWidgetListener) {
|
|
|
|
mWidgetListener->WindowResized(this, aSize.width, aSize.height);
|
|
|
|
}
|
2016-02-01 22:38:14 +00:00
|
|
|
|
|
|
|
if (mAttachedWidgetListener) {
|
|
|
|
mAttachedWidgetListener->WindowResized(this, aSize.width, aSize.height);
|
|
|
|
}
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-11-10 05:37:32 +00:00
|
|
|
nsWindow::InitEvent(WidgetGUIEvent& event, LayoutDeviceIntPoint* aPoint)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
|
|
|
if (aPoint) {
|
2016-04-18 14:09:02 +00:00
|
|
|
event.mRefPoint = *aPoint;
|
2010-06-03 20:56:36 +00:00
|
|
|
} else {
|
2016-04-18 14:09:02 +00:00
|
|
|
event.mRefPoint = LayoutDeviceIntPoint(0, 0);
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2016-03-28 04:29:42 +00:00
|
|
|
event.mTime = PR_Now() / 1000;
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2016-01-26 01:30:55 +00:00
|
|
|
void
|
|
|
|
nsWindow::UpdateOverscrollVelocity(const float aX, const float aY)
|
|
|
|
{
|
2016-08-18 22:03:04 +00:00
|
|
|
if (NativePtr<NPZCSupport>::Locked npzcs{mNPZCSupport}) {
|
|
|
|
npzcs->UpdateOverscrollVelocity(aX, aY);
|
2016-01-26 01:30:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::UpdateOverscrollOffset(const float aX, const float aY)
|
|
|
|
{
|
2016-08-18 22:03:04 +00:00
|
|
|
if (NativePtr<NPZCSupport>::Locked npzcs{mNPZCSupport}) {
|
|
|
|
npzcs->UpdateOverscrollOffset(aX, aY);
|
2016-01-26 01:30:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-24 22:00:27 +00:00
|
|
|
void
|
|
|
|
nsWindow::SetScrollingRootContent(const bool isRootContent)
|
|
|
|
{
|
|
|
|
// On Android, the Controller thread and UI thread are the same.
|
|
|
|
MOZ_ASSERT(APZThreadUtils::IsControllerThread(), "nsWindow::SetScrollingRootContent must be called from the controller thread");
|
|
|
|
|
2016-08-18 22:03:04 +00:00
|
|
|
if (NativePtr<NPZCSupport>::Locked npzcs{mNPZCSupport}) {
|
|
|
|
npzcs->SetScrollingRootContent(isRootContent);
|
2016-03-24 22:00:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-10 23:06:13 +00:00
|
|
|
void
|
|
|
|
nsWindow::SetSelectionDragState(bool aState)
|
|
|
|
{
|
2016-08-18 22:03:04 +00:00
|
|
|
if (NativePtr<NPZCSupport>::Locked npzcs{mNPZCSupport}) {
|
|
|
|
npzcs->SetSelectionDragState(aState);
|
2016-03-10 23:06:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-03 20:56:36 +00:00
|
|
|
void *
|
2012-08-22 15:56:38 +00:00
|
|
|
nsWindow::GetNativeData(uint32_t aDataType)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
|
|
|
switch (aDataType) {
|
2013-10-10 20:42:52 +00:00
|
|
|
// used by GLContextProviderEGL, nullptr is EGL_DEFAULT_DISPLAY
|
2010-06-26 00:52:37 +00:00
|
|
|
case NS_NATIVE_DISPLAY:
|
2013-10-10 20:42:52 +00:00
|
|
|
return nullptr;
|
2010-06-26 00:52:37 +00:00
|
|
|
|
2010-06-03 20:56:36 +00:00
|
|
|
case NS_NATIVE_WIDGET:
|
|
|
|
return (void *) this;
|
2015-12-11 06:15:57 +00:00
|
|
|
|
2016-03-16 04:47:47 +00:00
|
|
|
case NS_RAW_NATIVE_IME_CONTEXT: {
|
|
|
|
void* pseudoIMEContext = GetPseudoIMEContext();
|
|
|
|
if (pseudoIMEContext) {
|
|
|
|
return pseudoIMEContext;
|
|
|
|
}
|
2015-12-11 06:15:57 +00:00
|
|
|
// We assume that there is only one context per process on Android
|
|
|
|
return NS_ONLY_ONE_NATIVE_IME_CONTEXT;
|
2016-03-16 04:47:47 +00:00
|
|
|
}
|
2015-12-11 06:15:57 +00:00
|
|
|
|
2016-06-08 13:38:45 +00:00
|
|
|
case NS_JAVA_SURFACE:
|
2016-08-18 22:03:04 +00:00
|
|
|
if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
|
|
|
|
return lvs->GetSurface().Get();
|
2015-12-24 03:03:34 +00:00
|
|
|
}
|
2016-08-18 22:03:04 +00:00
|
|
|
return nullptr;
|
2016-08-19 21:17:24 +00:00
|
|
|
|
|
|
|
case NS_PRESENTATION_WINDOW:
|
|
|
|
return PMPMSupport::sWindow;
|
|
|
|
|
|
|
|
case NS_PRESENTATION_SURFACE:
|
|
|
|
return PMPMSupport::sSurface;
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2016-08-19 21:17:24 +00:00
|
|
|
void
|
|
|
|
nsWindow::SetNativeData(uint32_t aDataType, uintptr_t aVal)
|
|
|
|
{
|
|
|
|
switch (aDataType) {
|
|
|
|
case NS_PRESENTATION_SURFACE:
|
|
|
|
PMPMSupport::sSurface = reinterpret_cast<EGLSurface>(aVal);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-13 20:10:51 +00:00
|
|
|
void
|
|
|
|
nsWindow::DispatchHitTest(const WidgetTouchEvent& aEvent)
|
|
|
|
{
|
2016-03-30 09:44:28 +00:00
|
|
|
if (aEvent.mMessage == eTouchStart && aEvent.mTouches.Length() == 1) {
|
2015-11-13 20:10:51 +00:00
|
|
|
// Since touch events don't get retargeted by PositionedEventTargeting.cpp
|
|
|
|
// code on Fennec, we dispatch a dummy mouse event that *does* get
|
|
|
|
// retargeted. The Fennec browser.js code can use this to activate the
|
|
|
|
// highlight element in case the this touchstart is the start of a tap.
|
|
|
|
WidgetMouseEvent hittest(true, eMouseHitTest, this,
|
|
|
|
WidgetMouseEvent::eReal);
|
2016-04-18 14:09:02 +00:00
|
|
|
hittest.mRefPoint = aEvent.mTouches[0]->mRefPoint;
|
2016-05-10 12:15:05 +00:00
|
|
|
hittest.mIgnoreRootScrollFrame = true;
|
2015-11-13 20:10:51 +00:00
|
|
|
hittest.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
|
|
|
|
nsEventStatus status;
|
|
|
|
DispatchEvent(&hittest, status);
|
2015-11-13 20:10:52 +00:00
|
|
|
|
|
|
|
if (mAPZEventState && hittest.hitCluster) {
|
|
|
|
mAPZEventState->ProcessClusterHit();
|
|
|
|
}
|
2015-11-13 20:10:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-19 20:34:03 +00:00
|
|
|
static unsigned int ConvertAndroidKeyCodeToDOMKeyCode(int androidKeyCode)
|
|
|
|
{
|
|
|
|
// Special-case alphanumeric keycodes because they are most common.
|
2013-04-22 18:24:43 +00:00
|
|
|
if (androidKeyCode >= AKEYCODE_A &&
|
|
|
|
androidKeyCode <= AKEYCODE_Z) {
|
|
|
|
return androidKeyCode - AKEYCODE_A + NS_VK_A;
|
2012-04-19 20:34:03 +00:00
|
|
|
}
|
|
|
|
|
2013-04-22 18:24:43 +00:00
|
|
|
if (androidKeyCode >= AKEYCODE_0 &&
|
|
|
|
androidKeyCode <= AKEYCODE_9) {
|
|
|
|
return androidKeyCode - AKEYCODE_0 + NS_VK_0;
|
2012-04-19 20:34:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (androidKeyCode) {
|
2012-04-25 03:47:46 +00:00
|
|
|
// KEYCODE_UNKNOWN (0) ... KEYCODE_HOME (3)
|
2013-04-22 18:24:43 +00:00
|
|
|
case AKEYCODE_BACK: return NS_VK_ESCAPE;
|
2012-04-25 03:47:46 +00:00
|
|
|
// KEYCODE_CALL (5) ... KEYCODE_POUND (18)
|
2013-04-22 18:24:43 +00:00
|
|
|
case AKEYCODE_DPAD_UP: return NS_VK_UP;
|
|
|
|
case AKEYCODE_DPAD_DOWN: return NS_VK_DOWN;
|
|
|
|
case AKEYCODE_DPAD_LEFT: return NS_VK_LEFT;
|
|
|
|
case AKEYCODE_DPAD_RIGHT: return NS_VK_RIGHT;
|
|
|
|
case AKEYCODE_DPAD_CENTER: return NS_VK_RETURN;
|
|
|
|
case AKEYCODE_VOLUME_UP: return NS_VK_VOLUME_UP;
|
|
|
|
case AKEYCODE_VOLUME_DOWN: return NS_VK_VOLUME_DOWN;
|
2013-02-04 23:27:56 +00:00
|
|
|
// KEYCODE_VOLUME_POWER (26) ... KEYCODE_Z (54)
|
2013-04-22 18:24:43 +00:00
|
|
|
case AKEYCODE_COMMA: return NS_VK_COMMA;
|
|
|
|
case AKEYCODE_PERIOD: return NS_VK_PERIOD;
|
|
|
|
case AKEYCODE_ALT_LEFT: return NS_VK_ALT;
|
|
|
|
case AKEYCODE_ALT_RIGHT: return NS_VK_ALT;
|
|
|
|
case AKEYCODE_SHIFT_LEFT: return NS_VK_SHIFT;
|
|
|
|
case AKEYCODE_SHIFT_RIGHT: return NS_VK_SHIFT;
|
|
|
|
case AKEYCODE_TAB: return NS_VK_TAB;
|
|
|
|
case AKEYCODE_SPACE: return NS_VK_SPACE;
|
2012-04-19 20:34:03 +00:00
|
|
|
// KEYCODE_SYM (63) ... KEYCODE_ENVELOPE (65)
|
2013-04-22 18:24:43 +00:00
|
|
|
case AKEYCODE_ENTER: return NS_VK_RETURN;
|
|
|
|
case AKEYCODE_DEL: return NS_VK_BACK; // Backspace
|
|
|
|
case AKEYCODE_GRAVE: return NS_VK_BACK_QUOTE;
|
2012-04-19 20:34:03 +00:00
|
|
|
// KEYCODE_MINUS (69)
|
2013-04-22 18:24:43 +00:00
|
|
|
case AKEYCODE_EQUALS: return NS_VK_EQUALS;
|
|
|
|
case AKEYCODE_LEFT_BRACKET: return NS_VK_OPEN_BRACKET;
|
|
|
|
case AKEYCODE_RIGHT_BRACKET: return NS_VK_CLOSE_BRACKET;
|
|
|
|
case AKEYCODE_BACKSLASH: return NS_VK_BACK_SLASH;
|
|
|
|
case AKEYCODE_SEMICOLON: return NS_VK_SEMICOLON;
|
2012-04-19 20:34:03 +00:00
|
|
|
// KEYCODE_APOSTROPHE (75)
|
2013-04-22 18:24:43 +00:00
|
|
|
case AKEYCODE_SLASH: return NS_VK_SLASH;
|
2013-02-04 23:27:56 +00:00
|
|
|
// KEYCODE_AT (77) ... KEYCODE_MEDIA_FAST_FORWARD (90)
|
2013-04-22 18:24:43 +00:00
|
|
|
case AKEYCODE_MUTE: return NS_VK_VOLUME_MUTE;
|
|
|
|
case AKEYCODE_PAGE_UP: return NS_VK_PAGE_UP;
|
|
|
|
case AKEYCODE_PAGE_DOWN: return NS_VK_PAGE_DOWN;
|
2012-04-19 20:34:03 +00:00
|
|
|
// KEYCODE_PICTSYMBOLS (94) ... KEYCODE_BUTTON_MODE (110)
|
2013-04-22 18:24:43 +00:00
|
|
|
case AKEYCODE_ESCAPE: return NS_VK_ESCAPE;
|
|
|
|
case AKEYCODE_FORWARD_DEL: return NS_VK_DELETE;
|
|
|
|
case AKEYCODE_CTRL_LEFT: return NS_VK_CONTROL;
|
|
|
|
case AKEYCODE_CTRL_RIGHT: return NS_VK_CONTROL;
|
|
|
|
case AKEYCODE_CAPS_LOCK: return NS_VK_CAPS_LOCK;
|
|
|
|
case AKEYCODE_SCROLL_LOCK: return NS_VK_SCROLL_LOCK;
|
2012-04-19 20:34:03 +00:00
|
|
|
// KEYCODE_META_LEFT (117) ... KEYCODE_FUNCTION (119)
|
2013-04-22 18:24:43 +00:00
|
|
|
case AKEYCODE_SYSRQ: return NS_VK_PRINTSCREEN;
|
|
|
|
case AKEYCODE_BREAK: return NS_VK_PAUSE;
|
|
|
|
case AKEYCODE_MOVE_HOME: return NS_VK_HOME;
|
|
|
|
case AKEYCODE_MOVE_END: return NS_VK_END;
|
|
|
|
case AKEYCODE_INSERT: return NS_VK_INSERT;
|
2012-04-19 20:34:03 +00:00
|
|
|
// KEYCODE_FORWARD (125) ... KEYCODE_MEDIA_RECORD (130)
|
2013-04-22 18:24:43 +00:00
|
|
|
case AKEYCODE_F1: return NS_VK_F1;
|
|
|
|
case AKEYCODE_F2: return NS_VK_F2;
|
|
|
|
case AKEYCODE_F3: return NS_VK_F3;
|
|
|
|
case AKEYCODE_F4: return NS_VK_F4;
|
|
|
|
case AKEYCODE_F5: return NS_VK_F5;
|
|
|
|
case AKEYCODE_F6: return NS_VK_F6;
|
|
|
|
case AKEYCODE_F7: return NS_VK_F7;
|
|
|
|
case AKEYCODE_F8: return NS_VK_F8;
|
|
|
|
case AKEYCODE_F9: return NS_VK_F9;
|
|
|
|
case AKEYCODE_F10: return NS_VK_F10;
|
|
|
|
case AKEYCODE_F11: return NS_VK_F11;
|
|
|
|
case AKEYCODE_F12: return NS_VK_F12;
|
|
|
|
case AKEYCODE_NUM_LOCK: return NS_VK_NUM_LOCK;
|
|
|
|
case AKEYCODE_NUMPAD_0: return NS_VK_NUMPAD0;
|
|
|
|
case AKEYCODE_NUMPAD_1: return NS_VK_NUMPAD1;
|
|
|
|
case AKEYCODE_NUMPAD_2: return NS_VK_NUMPAD2;
|
|
|
|
case AKEYCODE_NUMPAD_3: return NS_VK_NUMPAD3;
|
|
|
|
case AKEYCODE_NUMPAD_4: return NS_VK_NUMPAD4;
|
|
|
|
case AKEYCODE_NUMPAD_5: return NS_VK_NUMPAD5;
|
|
|
|
case AKEYCODE_NUMPAD_6: return NS_VK_NUMPAD6;
|
|
|
|
case AKEYCODE_NUMPAD_7: return NS_VK_NUMPAD7;
|
|
|
|
case AKEYCODE_NUMPAD_8: return NS_VK_NUMPAD8;
|
|
|
|
case AKEYCODE_NUMPAD_9: return NS_VK_NUMPAD9;
|
|
|
|
case AKEYCODE_NUMPAD_DIVIDE: return NS_VK_DIVIDE;
|
|
|
|
case AKEYCODE_NUMPAD_MULTIPLY: return NS_VK_MULTIPLY;
|
|
|
|
case AKEYCODE_NUMPAD_SUBTRACT: return NS_VK_SUBTRACT;
|
|
|
|
case AKEYCODE_NUMPAD_ADD: return NS_VK_ADD;
|
|
|
|
case AKEYCODE_NUMPAD_DOT: return NS_VK_DECIMAL;
|
|
|
|
case AKEYCODE_NUMPAD_COMMA: return NS_VK_SEPARATOR;
|
|
|
|
case AKEYCODE_NUMPAD_ENTER: return NS_VK_RETURN;
|
|
|
|
case AKEYCODE_NUMPAD_EQUALS: return NS_VK_EQUALS;
|
2012-04-19 20:34:03 +00:00
|
|
|
// KEYCODE_NUMPAD_LEFT_PAREN (162) ... KEYCODE_CALCULATOR (210)
|
|
|
|
|
2013-04-24 03:49:48 +00:00
|
|
|
// Needs to confirm the behavior. If the key switches the open state
|
|
|
|
// of Japanese IME (or switches input character between Hiragana and
|
|
|
|
// Roman numeric characters), then, it might be better to use
|
|
|
|
// NS_VK_KANJI which is used for Alt+Zenkaku/Hankaku key on Windows.
|
|
|
|
case AKEYCODE_ZENKAKU_HANKAKU: return 0;
|
|
|
|
case AKEYCODE_EISU: return NS_VK_EISU;
|
|
|
|
case AKEYCODE_MUHENKAN: return NS_VK_NONCONVERT;
|
|
|
|
case AKEYCODE_HENKAN: return NS_VK_CONVERT;
|
|
|
|
case AKEYCODE_KATAKANA_HIRAGANA: return 0;
|
|
|
|
case AKEYCODE_YEN: return NS_VK_BACK_SLASH; // Same as other platforms.
|
|
|
|
case AKEYCODE_RO: return NS_VK_BACK_SLASH; // Same as other platforms.
|
|
|
|
case AKEYCODE_KANA: return NS_VK_KANA;
|
|
|
|
case AKEYCODE_ASSIST: return NS_VK_HELP;
|
|
|
|
|
2013-10-12 17:59:50 +00:00
|
|
|
// the A key is the action key for gamepad devices.
|
|
|
|
case AKEYCODE_BUTTON_A: return NS_VK_RETURN;
|
|
|
|
|
2012-04-19 20:34:03 +00:00
|
|
|
default:
|
|
|
|
ALOG("ConvertAndroidKeyCodeToDOMKeyCode: "
|
|
|
|
"No DOM keycode for Android keycode %d", androidKeyCode);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-10 16:14:54 +00:00
|
|
|
static KeyNameIndex
|
2015-10-22 21:45:46 +00:00
|
|
|
ConvertAndroidKeyCodeToKeyNameIndex(int keyCode, int action,
|
|
|
|
int domPrintableKeyValue)
|
2013-04-24 03:49:48 +00:00
|
|
|
{
|
|
|
|
// Special-case alphanumeric keycodes because they are most common.
|
2013-12-10 16:14:54 +00:00
|
|
|
if (keyCode >= AKEYCODE_A && keyCode <= AKEYCODE_Z) {
|
|
|
|
return KEY_NAME_INDEX_USE_STRING;
|
2013-04-24 03:49:48 +00:00
|
|
|
}
|
|
|
|
|
2013-12-10 16:14:54 +00:00
|
|
|
if (keyCode >= AKEYCODE_0 && keyCode <= AKEYCODE_9) {
|
|
|
|
return KEY_NAME_INDEX_USE_STRING;
|
2013-04-24 03:49:48 +00:00
|
|
|
}
|
|
|
|
|
2013-12-10 16:14:54 +00:00
|
|
|
switch (keyCode) {
|
2013-04-24 03:49:48 +00:00
|
|
|
|
|
|
|
#define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \
|
|
|
|
case aNativeKey: return aKeyNameIndex;
|
|
|
|
|
|
|
|
#include "NativeKeyToDOMKeyName.h"
|
|
|
|
|
|
|
|
#undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX
|
|
|
|
|
|
|
|
// KEYCODE_0 (7) ... KEYCODE_9 (16)
|
|
|
|
case AKEYCODE_STAR: // '*' key
|
|
|
|
case AKEYCODE_POUND: // '#' key
|
|
|
|
|
|
|
|
// KEYCODE_A (29) ... KEYCODE_Z (54)
|
|
|
|
|
|
|
|
case AKEYCODE_COMMA: // ',' key
|
|
|
|
case AKEYCODE_PERIOD: // '.' key
|
2013-12-10 16:14:54 +00:00
|
|
|
case AKEYCODE_SPACE:
|
2013-04-24 03:49:48 +00:00
|
|
|
case AKEYCODE_GRAVE: // '`' key
|
|
|
|
case AKEYCODE_MINUS: // '-' key
|
|
|
|
case AKEYCODE_EQUALS: // '=' key
|
|
|
|
case AKEYCODE_LEFT_BRACKET: // '[' key
|
|
|
|
case AKEYCODE_RIGHT_BRACKET: // ']' key
|
|
|
|
case AKEYCODE_BACKSLASH: // '\' key
|
|
|
|
case AKEYCODE_SEMICOLON: // ';' key
|
|
|
|
case AKEYCODE_APOSTROPHE: // ''' key
|
|
|
|
case AKEYCODE_SLASH: // '/' key
|
|
|
|
case AKEYCODE_AT: // '@' key
|
|
|
|
case AKEYCODE_PLUS: // '+' key
|
|
|
|
|
|
|
|
case AKEYCODE_NUMPAD_0:
|
|
|
|
case AKEYCODE_NUMPAD_1:
|
|
|
|
case AKEYCODE_NUMPAD_2:
|
|
|
|
case AKEYCODE_NUMPAD_3:
|
|
|
|
case AKEYCODE_NUMPAD_4:
|
|
|
|
case AKEYCODE_NUMPAD_5:
|
|
|
|
case AKEYCODE_NUMPAD_6:
|
|
|
|
case AKEYCODE_NUMPAD_7:
|
|
|
|
case AKEYCODE_NUMPAD_8:
|
|
|
|
case AKEYCODE_NUMPAD_9:
|
2013-12-10 16:14:54 +00:00
|
|
|
case AKEYCODE_NUMPAD_DIVIDE:
|
|
|
|
case AKEYCODE_NUMPAD_MULTIPLY:
|
|
|
|
case AKEYCODE_NUMPAD_SUBTRACT:
|
|
|
|
case AKEYCODE_NUMPAD_ADD:
|
|
|
|
case AKEYCODE_NUMPAD_DOT:
|
|
|
|
case AKEYCODE_NUMPAD_COMMA:
|
|
|
|
case AKEYCODE_NUMPAD_EQUALS:
|
2013-04-24 03:49:48 +00:00
|
|
|
case AKEYCODE_NUMPAD_LEFT_PAREN:
|
|
|
|
case AKEYCODE_NUMPAD_RIGHT_PAREN:
|
|
|
|
|
|
|
|
case AKEYCODE_YEN: // yen sign key
|
|
|
|
case AKEYCODE_RO: // Japanese Ro key
|
2013-12-10 16:14:54 +00:00
|
|
|
return KEY_NAME_INDEX_USE_STRING;
|
2013-04-24 03:49:48 +00:00
|
|
|
|
|
|
|
case AKEYCODE_NUM: // XXX Not sure
|
|
|
|
case AKEYCODE_PICTSYMBOLS:
|
|
|
|
|
|
|
|
case AKEYCODE_BUTTON_A:
|
|
|
|
case AKEYCODE_BUTTON_B:
|
|
|
|
case AKEYCODE_BUTTON_C:
|
|
|
|
case AKEYCODE_BUTTON_X:
|
|
|
|
case AKEYCODE_BUTTON_Y:
|
|
|
|
case AKEYCODE_BUTTON_Z:
|
|
|
|
case AKEYCODE_BUTTON_L1:
|
|
|
|
case AKEYCODE_BUTTON_R1:
|
|
|
|
case AKEYCODE_BUTTON_L2:
|
|
|
|
case AKEYCODE_BUTTON_R2:
|
|
|
|
case AKEYCODE_BUTTON_THUMBL:
|
|
|
|
case AKEYCODE_BUTTON_THUMBR:
|
|
|
|
case AKEYCODE_BUTTON_START:
|
|
|
|
case AKEYCODE_BUTTON_SELECT:
|
|
|
|
case AKEYCODE_BUTTON_MODE:
|
|
|
|
|
|
|
|
case AKEYCODE_MEDIA_CLOSE:
|
|
|
|
|
|
|
|
case AKEYCODE_BUTTON_1:
|
|
|
|
case AKEYCODE_BUTTON_2:
|
|
|
|
case AKEYCODE_BUTTON_3:
|
|
|
|
case AKEYCODE_BUTTON_4:
|
|
|
|
case AKEYCODE_BUTTON_5:
|
|
|
|
case AKEYCODE_BUTTON_6:
|
|
|
|
case AKEYCODE_BUTTON_7:
|
|
|
|
case AKEYCODE_BUTTON_8:
|
|
|
|
case AKEYCODE_BUTTON_9:
|
|
|
|
case AKEYCODE_BUTTON_10:
|
|
|
|
case AKEYCODE_BUTTON_11:
|
|
|
|
case AKEYCODE_BUTTON_12:
|
|
|
|
case AKEYCODE_BUTTON_13:
|
|
|
|
case AKEYCODE_BUTTON_14:
|
|
|
|
case AKEYCODE_BUTTON_15:
|
|
|
|
case AKEYCODE_BUTTON_16:
|
|
|
|
return KEY_NAME_INDEX_Unidentified;
|
|
|
|
|
2013-12-10 16:14:54 +00:00
|
|
|
case AKEYCODE_UNKNOWN:
|
|
|
|
MOZ_ASSERT(
|
2015-10-22 21:45:46 +00:00
|
|
|
action != AKEY_EVENT_ACTION_MULTIPLE,
|
2013-12-10 16:14:54 +00:00
|
|
|
"Don't call this when action is AKEY_EVENT_ACTION_MULTIPLE!");
|
|
|
|
// It's actually an unknown key if the action isn't ACTION_MULTIPLE.
|
|
|
|
// However, it might cause text input. So, let's check the value.
|
2015-10-22 21:45:46 +00:00
|
|
|
return domPrintableKeyValue ?
|
2013-12-10 16:14:54 +00:00
|
|
|
KEY_NAME_INDEX_USE_STRING : KEY_NAME_INDEX_Unidentified;
|
|
|
|
|
2013-04-24 03:49:48 +00:00
|
|
|
default:
|
|
|
|
ALOG("ConvertAndroidKeyCodeToKeyNameIndex: "
|
2013-12-10 16:14:54 +00:00
|
|
|
"No DOM key name index for Android keycode %d", keyCode);
|
2013-04-24 03:49:48 +00:00
|
|
|
return KEY_NAME_INDEX_Unidentified;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-25 02:09:00 +00:00
|
|
|
static CodeNameIndex
|
2015-10-22 21:45:46 +00:00
|
|
|
ConvertAndroidScanCodeToCodeNameIndex(int scanCode)
|
2014-05-25 02:09:00 +00:00
|
|
|
{
|
2015-10-22 21:45:46 +00:00
|
|
|
switch (scanCode) {
|
2014-05-25 02:09:00 +00:00
|
|
|
|
|
|
|
#define NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX(aNativeKey, aCodeNameIndex) \
|
|
|
|
case aNativeKey: return aCodeNameIndex;
|
|
|
|
|
|
|
|
#include "NativeKeyToDOMCodeName.h"
|
|
|
|
|
|
|
|
#undef NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX
|
|
|
|
|
|
|
|
default:
|
|
|
|
return CODE_NAME_INDEX_UNKNOWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
static bool
|
|
|
|
IsModifierKey(int32_t keyCode)
|
2012-04-19 17:49:31 +00:00
|
|
|
{
|
2016-07-21 17:49:04 +00:00
|
|
|
using mozilla::java::sdk::KeyEvent;
|
2015-10-22 21:45:46 +00:00
|
|
|
return keyCode == KeyEvent::KEYCODE_ALT_LEFT ||
|
|
|
|
keyCode == KeyEvent::KEYCODE_ALT_RIGHT ||
|
|
|
|
keyCode == KeyEvent::KEYCODE_SHIFT_LEFT ||
|
|
|
|
keyCode == KeyEvent::KEYCODE_SHIFT_RIGHT ||
|
|
|
|
keyCode == KeyEvent::KEYCODE_CTRL_LEFT ||
|
|
|
|
keyCode == KeyEvent::KEYCODE_CTRL_RIGHT ||
|
|
|
|
keyCode == KeyEvent::KEYCODE_META_LEFT ||
|
|
|
|
keyCode == KeyEvent::KEYCODE_META_RIGHT;
|
|
|
|
}
|
2012-04-19 17:49:31 +00:00
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
static Modifiers
|
|
|
|
GetModifiers(int32_t metaState)
|
|
|
|
{
|
2016-07-21 17:49:04 +00:00
|
|
|
using mozilla::java::sdk::KeyEvent;
|
2015-10-22 21:45:46 +00:00
|
|
|
return (metaState & KeyEvent::META_ALT_MASK ? MODIFIER_ALT : 0)
|
|
|
|
| (metaState & KeyEvent::META_SHIFT_MASK ? MODIFIER_SHIFT : 0)
|
|
|
|
| (metaState & KeyEvent::META_CTRL_MASK ? MODIFIER_CONTROL : 0)
|
|
|
|
| (metaState & KeyEvent::META_META_MASK ? MODIFIER_META : 0)
|
|
|
|
| (metaState & KeyEvent::META_FUNCTION_ON ? MODIFIER_FN : 0)
|
|
|
|
| (metaState & KeyEvent::META_CAPS_LOCK_ON ? MODIFIER_CAPSLOCK : 0)
|
|
|
|
| (metaState & KeyEvent::META_NUM_LOCK_ON ? MODIFIER_NUMLOCK : 0)
|
|
|
|
| (metaState & KeyEvent::META_SCROLL_LOCK_ON ? MODIFIER_SCROLLLOCK : 0);
|
2012-04-19 17:49:31 +00:00
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
static void
|
|
|
|
InitKeyEvent(WidgetKeyboardEvent& event,
|
|
|
|
int32_t action, int32_t keyCode, int32_t scanCode,
|
|
|
|
int32_t metaState, int64_t time, int32_t unicodeChar,
|
|
|
|
int32_t baseUnicodeChar, int32_t domPrintableKeyValue,
|
|
|
|
int32_t repeatCount, int32_t flags)
|
|
|
|
{
|
|
|
|
const uint32_t domKeyCode = ConvertAndroidKeyCodeToDOMKeyCode(keyCode);
|
|
|
|
const int32_t charCode = unicodeChar ? unicodeChar : baseUnicodeChar;
|
|
|
|
|
2016-03-31 08:03:00 +00:00
|
|
|
event.mModifiers = GetModifiers(metaState);
|
2012-04-19 17:49:31 +00:00
|
|
|
|
2015-08-28 23:58:27 +00:00
|
|
|
if (event.mMessage == eKeyPress) {
|
2012-04-19 17:49:31 +00:00
|
|
|
// Android gives us \n, so filter out some control characters.
|
2016-05-12 09:31:05 +00:00
|
|
|
event.mIsChar = (charCode >= ' ');
|
|
|
|
event.mCharCode = event.mIsChar ? charCode : 0;
|
|
|
|
event.mKeyCode = event.mIsChar ? 0 : domKeyCode;
|
2014-07-23 19:55:51 +00:00
|
|
|
event.mPluginEvent.Clear();
|
2012-04-19 17:49:31 +00:00
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
// For keypress, if the unicode char already has modifiers applied, we
|
|
|
|
// don't specify extra modifiers. If UnicodeChar() != BaseUnicodeChar()
|
|
|
|
// it means UnicodeChar() already has modifiers applied.
|
|
|
|
// Note that on Android 4.x, Alt modifier isn't set when the key input
|
|
|
|
// causes text input even while right Alt key is pressed. However,
|
|
|
|
// this is necessary for Android 2.3 compatibility.
|
|
|
|
if (unicodeChar && unicodeChar != baseUnicodeChar) {
|
2016-03-31 08:03:00 +00:00
|
|
|
event.mModifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL
|
|
|
|
| MODIFIER_META);
|
2015-10-22 21:45:46 +00:00
|
|
|
}
|
2012-04-19 17:49:31 +00:00
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
} else {
|
2016-05-12 09:31:05 +00:00
|
|
|
event.mIsChar = false;
|
2016-05-13 07:06:18 +00:00
|
|
|
event.mCharCode = 0;
|
2016-05-12 08:13:49 +00:00
|
|
|
event.mKeyCode = domKeyCode;
|
2012-04-19 17:49:31 +00:00
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
ANPEvent pluginEvent;
|
|
|
|
pluginEvent.inSize = sizeof(pluginEvent);
|
|
|
|
pluginEvent.eventType = kKey_ANPEventType;
|
|
|
|
pluginEvent.data.key.action = event.mMessage == eKeyDown
|
|
|
|
? kDown_ANPKeyAction : kUp_ANPKeyAction;
|
|
|
|
pluginEvent.data.key.nativeCode = keyCode;
|
|
|
|
pluginEvent.data.key.virtualCode = domKeyCode;
|
|
|
|
pluginEvent.data.key.unichar = charCode;
|
|
|
|
pluginEvent.data.key.modifiers =
|
|
|
|
(metaState & sdk::KeyEvent::META_SHIFT_MASK
|
|
|
|
? kShift_ANPKeyModifier : 0) |
|
|
|
|
(metaState & sdk::KeyEvent::META_ALT_MASK
|
|
|
|
? kAlt_ANPKeyModifier : 0);
|
|
|
|
pluginEvent.data.key.repeatCount = repeatCount;
|
|
|
|
event.mPluginEvent.Copy(pluginEvent);
|
2013-03-29 14:54:01 +00:00
|
|
|
}
|
2013-11-07 11:17:33 +00:00
|
|
|
|
|
|
|
event.mIsRepeat =
|
2015-08-28 23:58:27 +00:00
|
|
|
(event.mMessage == eKeyDown || event.mMessage == eKeyPress) &&
|
2015-10-22 21:45:46 +00:00
|
|
|
((flags & sdk::KeyEvent::FLAG_LONG_PRESS) || repeatCount);
|
2010-10-16 12:15:54 +00:00
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
event.mKeyNameIndex = ConvertAndroidKeyCodeToKeyNameIndex(
|
|
|
|
keyCode, action, domPrintableKeyValue);
|
|
|
|
event.mCodeNameIndex = ConvertAndroidScanCodeToCodeNameIndex(scanCode);
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
if (event.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING &&
|
|
|
|
domPrintableKeyValue) {
|
|
|
|
event.mKeyValue = char16_t(domPrintableKeyValue);
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2016-05-12 09:17:22 +00:00
|
|
|
event.mLocation =
|
2015-10-22 21:45:46 +00:00
|
|
|
WidgetKeyboardEvent::ComputeLocationFromCodeValue(event.mCodeNameIndex);
|
2016-03-28 04:29:42 +00:00
|
|
|
event.mTime = time;
|
2016-12-27 01:59:15 +00:00
|
|
|
event.mTimeStamp = GetEventTimeStamp(time);
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-12-24 03:03:34 +00:00
|
|
|
nsWindow::GeckoViewSupport::OnKeyEvent(int32_t aAction, int32_t aKeyCode,
|
2015-10-22 21:45:46 +00:00
|
|
|
int32_t aScanCode, int32_t aMetaState, int64_t aTime,
|
|
|
|
int32_t aUnicodeChar, int32_t aBaseUnicodeChar,
|
|
|
|
int32_t aDomPrintableKeyValue, int32_t aRepeatCount, int32_t aFlags,
|
2016-03-01 12:49:54 +00:00
|
|
|
bool aIsSynthesizedImeKey, jni::Object::Param originalEvent)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2015-10-22 21:45:46 +00:00
|
|
|
RefPtr<nsWindow> kungFuDeathGrip(&window);
|
2016-03-11 18:47:22 +00:00
|
|
|
if (!aIsSynthesizedImeKey) {
|
|
|
|
window.UserActivity();
|
|
|
|
window.RemoveIMEComposition();
|
|
|
|
}
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2015-08-26 12:56:59 +00:00
|
|
|
EventMessage msg;
|
2015-10-22 21:45:46 +00:00
|
|
|
if (aAction == sdk::KeyEvent::ACTION_DOWN) {
|
2015-08-28 23:58:27 +00:00
|
|
|
msg = eKeyDown;
|
2015-10-22 21:45:46 +00:00
|
|
|
} else if (aAction == sdk::KeyEvent::ACTION_UP) {
|
2015-08-28 23:58:27 +00:00
|
|
|
msg = eKeyUp;
|
2015-10-22 21:45:46 +00:00
|
|
|
} else if (aAction == sdk::KeyEvent::ACTION_MULTIPLE) {
|
2014-02-24 17:27:58 +00:00
|
|
|
// Keys with multiple action are handled in Java,
|
|
|
|
// and we should never see one here
|
|
|
|
MOZ_CRASH("Cannot handle key with multiple action");
|
2015-10-22 21:45:46 +00:00
|
|
|
} else {
|
2010-06-03 20:56:36 +00:00
|
|
|
ALOG("Unknown key action event!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
|
|
WidgetKeyboardEvent event(true, msg, &window);
|
|
|
|
window.InitEvent(event, nullptr);
|
2015-10-22 21:45:46 +00:00
|
|
|
InitKeyEvent(event, aAction, aKeyCode, aScanCode, aMetaState, aTime,
|
|
|
|
aUnicodeChar, aBaseUnicodeChar, aDomPrintableKeyValue,
|
|
|
|
aRepeatCount, aFlags);
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
if (aIsSynthesizedImeKey) {
|
2015-10-22 21:45:46 +00:00
|
|
|
// Keys synthesized by Java IME code are saved in the mIMEKeyEvents
|
|
|
|
// array until the next IME_REPLACE_TEXT event, at which point
|
|
|
|
// these keys are dispatched in sequence.
|
2015-10-22 21:45:47 +00:00
|
|
|
mIMEKeyEvents.AppendElement(
|
2015-10-22 21:45:46 +00:00
|
|
|
mozilla::UniquePtr<WidgetEvent>(event.Duplicate()));
|
2016-03-11 18:47:22 +00:00
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
} else {
|
|
|
|
window.DispatchEvent(&event, status);
|
2016-03-01 12:49:54 +00:00
|
|
|
|
2016-03-11 18:47:22 +00:00
|
|
|
if (window.Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
|
|
|
|
// Skip default processing.
|
|
|
|
return;
|
2016-03-01 12:49:54 +00:00
|
|
|
}
|
2016-03-11 18:47:22 +00:00
|
|
|
|
|
|
|
mEditable->OnDefaultKeyEvent(originalEvent);
|
2015-10-22 21:45:46 +00:00
|
|
|
}
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2016-03-11 18:47:22 +00:00
|
|
|
if (msg != eKeyDown || IsModifierKey(aKeyCode)) {
|
2015-10-22 21:45:46 +00:00
|
|
|
// Skip sending key press event.
|
2010-12-21 22:36:28 +00:00
|
|
|
return;
|
2013-07-25 06:09:28 +00:00
|
|
|
}
|
2010-12-21 22:36:28 +00:00
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
WidgetKeyboardEvent pressEvent(true, eKeyPress, &window);
|
|
|
|
window.InitEvent(pressEvent, nullptr);
|
2015-10-22 21:45:46 +00:00
|
|
|
InitKeyEvent(pressEvent, aAction, aKeyCode, aScanCode, aMetaState, aTime,
|
|
|
|
aUnicodeChar, aBaseUnicodeChar, aDomPrintableKeyValue,
|
|
|
|
aRepeatCount, aFlags);
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
if (aIsSynthesizedImeKey) {
|
2015-10-22 21:45:47 +00:00
|
|
|
mIMEKeyEvents.AppendElement(
|
2015-10-22 21:45:46 +00:00
|
|
|
mozilla::UniquePtr<WidgetEvent>(pressEvent.Duplicate()));
|
|
|
|
} else {
|
|
|
|
window.DispatchEvent(&pressEvent, status);
|
|
|
|
}
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2011-08-29 18:29:39 +00:00
|
|
|
#ifdef DEBUG_ANDROID_IME
|
2010-08-04 19:47:26 +00:00
|
|
|
#define ALOGIME(args...) ALOG(args)
|
|
|
|
#else
|
2013-01-25 19:33:40 +00:00
|
|
|
#define ALOGIME(args...) ((void)0)
|
2010-08-04 19:47:26 +00:00
|
|
|
#endif
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2012-11-01 20:11:02 +00:00
|
|
|
static nscolor
|
2015-10-22 21:45:47 +00:00
|
|
|
ConvertAndroidColor(uint32_t aArgb)
|
2012-11-01 20:11:02 +00:00
|
|
|
{
|
2015-10-22 21:45:47 +00:00
|
|
|
return NS_RGBA((aArgb & 0x00ff0000) >> 16,
|
|
|
|
(aArgb & 0x0000ff00) >> 8,
|
|
|
|
(aArgb & 0x000000ff),
|
|
|
|
(aArgb & 0xff000000) >> 24);
|
2012-11-01 20:11:02 +00:00
|
|
|
}
|
|
|
|
|
2015-03-31 22:20:27 +00:00
|
|
|
/*
|
|
|
|
* Get the current composition object, if any.
|
|
|
|
*/
|
2015-10-18 05:24:48 +00:00
|
|
|
RefPtr<mozilla::TextComposition>
|
2015-03-31 22:20:27 +00:00
|
|
|
nsWindow::GetIMEComposition()
|
|
|
|
{
|
2015-10-08 19:25:49 +00:00
|
|
|
MOZ_ASSERT(this == FindTopLevel());
|
2015-04-25 02:26:34 +00:00
|
|
|
return mozilla::IMEStateManager::GetTextCompositionFor(this);
|
2015-03-31 22:20:27 +00:00
|
|
|
}
|
|
|
|
|
2012-11-01 20:11:02 +00:00
|
|
|
/*
|
|
|
|
Remove the composition but leave the text content as-is
|
|
|
|
*/
|
2010-08-04 19:47:26 +00:00
|
|
|
void
|
2016-10-25 16:28:54 +00:00
|
|
|
nsWindow::RemoveIMEComposition(RemoveIMECompositionFlag aFlag)
|
Backout 533faa3c50ed, 718abc1bd4ad, af2d5272c06b, ad5554e1345d, c9ef1b41b829, d3a825311d11, 0a51bcb3eb9e, a01a327e8ec4, 973b0ed30b8b, 39851bbcfaa1 & a92d2d2a3b0e (bug 805162), d4884aab5ce6, 06fcbaf40cb4, daccc3fe7c70, 881eb2a2906e, 76232441ae06, 01ae34fa1b3f & 5f405fc4e323 (bug 783092), a03d8d4db1c2, 49beb3801192, 174634554a97, 0bd27e755a83, 19e8f151ca67, a6604e038bc0, ed3b8237e76e & 082cf8d72554 (bug 785945) for bustage or conflicting with backout of said bustage on a CLOSED TREE
2012-11-01 00:16:35 +00:00
|
|
|
{
|
2012-11-01 20:11:02 +00:00
|
|
|
// Remove composition on Gecko side
|
2015-10-27 18:22:05 +00:00
|
|
|
const RefPtr<mozilla::TextComposition> composition(GetIMEComposition());
|
|
|
|
if (!composition) {
|
2012-11-01 20:11:02 +00:00
|
|
|
return;
|
2015-03-31 22:20:27 +00:00
|
|
|
}
|
2012-11-01 20:11:02 +00:00
|
|
|
|
2015-10-18 05:24:48 +00:00
|
|
|
RefPtr<nsWindow> kungFuDeathGrip(this);
|
2015-10-27 18:22:05 +00:00
|
|
|
|
|
|
|
WidgetCompositionEvent compositionCommitEvent(
|
|
|
|
true, eCompositionCommit, this);
|
2016-10-25 16:28:54 +00:00
|
|
|
if (aFlag == COMMIT_IME_COMPOSITION) {
|
|
|
|
compositionCommitEvent.mMessage = eCompositionCommitAsIs;
|
|
|
|
}
|
2014-11-25 05:02:33 +00:00
|
|
|
InitEvent(compositionCommitEvent, nullptr);
|
|
|
|
DispatchEvent(&compositionCommitEvent);
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2015-06-16 23:02:39 +00:00
|
|
|
/*
|
|
|
|
* Send dummy key events for pages that are unaware of input events,
|
|
|
|
* to provide web compatibility for pages that depend on key events.
|
|
|
|
* Our dummy key events have 0 as the keycode.
|
|
|
|
*/
|
|
|
|
void
|
2015-12-24 03:03:34 +00:00
|
|
|
nsWindow::GeckoViewSupport::SendIMEDummyKeyEvents()
|
2015-06-16 23:02:39 +00:00
|
|
|
{
|
2015-10-22 21:45:47 +00:00
|
|
|
WidgetKeyboardEvent downEvent(true, eKeyDown, &window);
|
|
|
|
window.InitEvent(downEvent, nullptr);
|
2016-05-12 08:13:49 +00:00
|
|
|
MOZ_ASSERT(downEvent.mKeyCode == 0);
|
2015-10-22 21:45:47 +00:00
|
|
|
window.DispatchEvent(&downEvent);
|
2015-06-16 23:02:39 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
WidgetKeyboardEvent upEvent(true, eKeyUp, &window);
|
|
|
|
window.InitEvent(upEvent, nullptr);
|
2016-05-12 08:13:49 +00:00
|
|
|
MOZ_ASSERT(upEvent.mKeyCode == 0);
|
2015-10-22 21:45:47 +00:00
|
|
|
window.DispatchEvent(&upEvent);
|
2015-06-16 23:02:39 +00:00
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:46 +00:00
|
|
|
void
|
2015-12-24 03:03:34 +00:00
|
|
|
nsWindow::GeckoViewSupport::AddIMETextChange(const IMETextChange& aChange)
|
2015-10-22 21:45:46 +00:00
|
|
|
{
|
2015-10-22 21:45:47 +00:00
|
|
|
mIMETextChanges.AppendElement(aChange);
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2015-12-12 15:18:43 +00:00
|
|
|
// We may not be in the middle of flushing,
|
|
|
|
// in which case this flag is meaningless.
|
|
|
|
mIMETextChangedDuringFlush = true;
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
// Now that we added a new range we need to go back and
|
|
|
|
// update all the ranges before that.
|
|
|
|
// Ranges that have offsets which follow this new range
|
|
|
|
// need to be updated to reflect new offsets
|
|
|
|
const int32_t delta = aChange.mNewEnd - aChange.mOldEnd;
|
|
|
|
for (int32_t i = mIMETextChanges.Length() - 2; i >= 0; i--) {
|
|
|
|
IMETextChange& previousChange = mIMETextChanges[i];
|
|
|
|
if (previousChange.mStart > aChange.mOldEnd) {
|
|
|
|
previousChange.mStart += delta;
|
|
|
|
previousChange.mOldEnd += delta;
|
|
|
|
previousChange.mNewEnd += delta;
|
|
|
|
}
|
|
|
|
}
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
// Now go through all ranges to merge any ranges that are connected
|
|
|
|
// srcIndex is the index of the range to merge from
|
|
|
|
// dstIndex is the index of the range to potentially merge into
|
|
|
|
int32_t srcIndex = mIMETextChanges.Length() - 1;
|
|
|
|
int32_t dstIndex = srcIndex;
|
2015-10-22 21:45:46 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
while (--dstIndex >= 0) {
|
|
|
|
IMETextChange& src = mIMETextChanges[srcIndex];
|
|
|
|
IMETextChange& dst = mIMETextChanges[dstIndex];
|
|
|
|
// When merging a more recent change into an older
|
|
|
|
// change, we need to compare recent change's (start, oldEnd)
|
|
|
|
// range to the older change's (start, newEnd)
|
|
|
|
if (src.mOldEnd < dst.mStart || dst.mNewEnd < src.mStart) {
|
|
|
|
// No overlap between ranges
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// When merging two ranges, there are generally four posibilities:
|
|
|
|
// [----(----]----), (----[----]----),
|
|
|
|
// [----(----)----], (----[----)----]
|
|
|
|
// where [----] is the first range and (----) is the second range
|
|
|
|
// As seen above, the start of the merged range is always the lesser
|
|
|
|
// of the two start offsets. OldEnd and NewEnd then need to be
|
|
|
|
// adjusted separately depending on the case. In any case, the change
|
|
|
|
// in text length of the merged range should be the sum of text length
|
|
|
|
// changes of the two original ranges, i.e.,
|
|
|
|
// newNewEnd - newOldEnd == newEnd1 - oldEnd1 + newEnd2 - oldEnd2
|
|
|
|
dst.mStart = std::min(dst.mStart, src.mStart);
|
|
|
|
if (src.mOldEnd < dst.mNewEnd) {
|
|
|
|
// New range overlaps or is within previous range; merge
|
|
|
|
dst.mNewEnd += src.mNewEnd - src.mOldEnd;
|
|
|
|
} else { // src.mOldEnd >= dst.mNewEnd
|
|
|
|
// New range overlaps previous range; merge
|
|
|
|
dst.mOldEnd += src.mOldEnd - dst.mNewEnd;
|
|
|
|
dst.mNewEnd = src.mNewEnd;
|
|
|
|
}
|
|
|
|
// src merged to dst; delete src.
|
|
|
|
mIMETextChanges.RemoveElementAt(srcIndex);
|
|
|
|
// Any ranges that we skip over between src and dst are not mergeable
|
|
|
|
// so we can safely continue the merge starting at dst
|
|
|
|
srcIndex = dstIndex;
|
|
|
|
}
|
2015-10-22 21:45:46 +00:00
|
|
|
}
|
|
|
|
|
2010-06-03 20:56:36 +00:00
|
|
|
void
|
2016-01-07 02:33:18 +00:00
|
|
|
nsWindow::GeckoViewSupport::PostFlushIMEChanges()
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2016-01-07 02:33:18 +00:00
|
|
|
if (!mIMETextChanges.IsEmpty() || mIMESelectionChanged) {
|
2015-10-22 21:45:47 +00:00
|
|
|
// Already posted
|
2012-11-13 22:27:19 +00:00
|
|
|
return;
|
|
|
|
}
|
2014-09-04 18:38:18 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
// Keep a strong reference to the window to keep 'this' alive.
|
|
|
|
RefPtr<nsWindow> window(&this->window);
|
2014-09-04 18:38:18 +00:00
|
|
|
|
2016-01-07 02:33:18 +00:00
|
|
|
nsAppShell::PostEvent([this, window] {
|
2015-10-22 21:45:47 +00:00
|
|
|
if (!window->Destroyed()) {
|
2016-01-07 02:33:18 +00:00
|
|
|
FlushIMEChanges();
|
2012-10-31 21:35:31 +00:00
|
|
|
}
|
2015-10-22 21:45:47 +00:00
|
|
|
});
|
|
|
|
}
|
2014-09-04 18:38:18 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
void
|
2015-12-24 03:03:34 +00:00
|
|
|
nsWindow::GeckoViewSupport::FlushIMEChanges(FlushChangesFlag aFlags)
|
2015-10-22 21:45:47 +00:00
|
|
|
{
|
|
|
|
// Only send change notifications if we are *not* masking events,
|
|
|
|
// i.e. if we have a focused editor,
|
|
|
|
NS_ENSURE_TRUE_VOID(!mIMEMaskEventsCount);
|
2014-09-04 18:38:18 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
nsCOMPtr<nsISelection> imeSelection;
|
|
|
|
nsCOMPtr<nsIContent> imeRoot;
|
2014-09-04 18:38:18 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
// If we are receiving notifications, we must have selection/root content.
|
2017-01-24 22:59:54 +00:00
|
|
|
nsresult rv = IMEStateManager::GetFocusSelectionAndRoot(
|
|
|
|
getter_AddRefs(imeSelection), getter_AddRefs(imeRoot));
|
|
|
|
|
|
|
|
// With e10s enabled, GetFocusSelectionAndRoot will fail because the IME
|
|
|
|
// content observer is out of process.
|
|
|
|
const bool e10sEnabled = rv == NS_ERROR_NOT_AVAILABLE;
|
|
|
|
if (!e10sEnabled) {
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(rv);
|
|
|
|
}
|
2014-09-04 18:38:18 +00:00
|
|
|
|
2016-03-11 18:47:22 +00:00
|
|
|
// Make sure we still have a valid selection/root. We can potentially get
|
|
|
|
// a stale selection/root if the editor becomes hidden, for example.
|
2017-01-24 22:59:54 +00:00
|
|
|
NS_ENSURE_TRUE_VOID(e10sEnabled || imeRoot->IsInComposedDoc());
|
2016-03-11 18:47:22 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
RefPtr<nsWindow> kungFuDeathGrip(&window);
|
|
|
|
window.UserActivity();
|
2014-09-04 18:38:18 +00:00
|
|
|
|
2015-12-12 15:18:43 +00:00
|
|
|
struct TextRecord {
|
|
|
|
nsString text;
|
|
|
|
int32_t start;
|
|
|
|
int32_t oldEnd;
|
|
|
|
int32_t newEnd;
|
|
|
|
};
|
2016-02-02 15:36:30 +00:00
|
|
|
AutoTArray<TextRecord, 4> textTransaction;
|
2015-12-12 15:18:43 +00:00
|
|
|
if (mIMETextChanges.Length() > textTransaction.Capacity()) {
|
|
|
|
textTransaction.SetCapacity(mIMETextChanges.Length());
|
|
|
|
}
|
|
|
|
|
|
|
|
mIMETextChangedDuringFlush = false;
|
2015-06-16 23:02:39 +00:00
|
|
|
|
2016-01-07 02:33:18 +00:00
|
|
|
auto shouldAbort = [=] () -> bool {
|
|
|
|
if (!mIMETextChangedDuringFlush) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// A query event could have triggered more text changes to come in, as
|
|
|
|
// indicated by our flag. If that happens, try flushing IME changes
|
|
|
|
// again.
|
2017-01-13 19:39:27 +00:00
|
|
|
if (aFlags == FLUSH_FLAG_NONE) {
|
2016-01-07 02:33:18 +00:00
|
|
|
FlushIMEChanges(FLUSH_FLAG_RETRY);
|
|
|
|
} else {
|
|
|
|
// Don't retry if already retrying, to avoid infinite loops.
|
|
|
|
__android_log_print(ANDROID_LOG_WARN, "GeckoViewSupport",
|
|
|
|
"Already retrying IME flush");
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2015-12-12 15:18:43 +00:00
|
|
|
for (const IMETextChange &change : mIMETextChanges) {
|
2015-10-22 21:45:47 +00:00
|
|
|
if (change.mStart == change.mOldEnd &&
|
|
|
|
change.mStart == change.mNewEnd) {
|
|
|
|
continue;
|
2012-11-01 20:11:02 +00:00
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
WidgetQueryContentEvent event(true, eQueryTextContent, &window);
|
2012-11-01 20:11:02 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
if (change.mNewEnd != change.mStart) {
|
|
|
|
window.InitEvent(event, nullptr);
|
|
|
|
event.InitForQueryTextContent(change.mStart,
|
|
|
|
change.mNewEnd - change.mStart);
|
|
|
|
window.DispatchEvent(&event);
|
|
|
|
NS_ENSURE_TRUE_VOID(event.mSucceeded);
|
2017-01-24 22:59:54 +00:00
|
|
|
NS_ENSURE_TRUE_VOID(e10sEnabled || event.mReply.mContentsRoot == imeRoot.get());
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
2014-09-04 18:38:18 +00:00
|
|
|
|
2016-01-07 02:33:18 +00:00
|
|
|
if (shouldAbort()) {
|
2015-12-12 15:18:43 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
textTransaction.AppendElement(
|
|
|
|
TextRecord{event.mReply.mString, change.mStart,
|
|
|
|
change.mOldEnd, change.mNewEnd});
|
2015-10-22 21:45:47 +00:00
|
|
|
}
|
2015-12-12 15:18:43 +00:00
|
|
|
|
2016-02-09 22:27:28 +00:00
|
|
|
int32_t selStart = -1;
|
|
|
|
int32_t selEnd = -1;
|
2015-12-12 15:18:43 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
if (mIMESelectionChanged) {
|
|
|
|
WidgetQueryContentEvent event(true, eQuerySelectedText, &window);
|
|
|
|
window.InitEvent(event, nullptr);
|
|
|
|
window.DispatchEvent(&event);
|
2010-08-04 19:47:26 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
NS_ENSURE_TRUE_VOID(event.mSucceeded);
|
2017-01-24 22:59:54 +00:00
|
|
|
NS_ENSURE_TRUE_VOID(e10sEnabled || event.mReply.mContentsRoot == imeRoot.get());
|
2014-09-04 18:38:18 +00:00
|
|
|
|
2016-01-07 02:33:18 +00:00
|
|
|
if (shouldAbort()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
selStart = int32_t(event.GetSelectionStart());
|
|
|
|
selEnd = int32_t(event.GetSelectionEnd());
|
|
|
|
}
|
|
|
|
|
2017-01-13 19:39:27 +00:00
|
|
|
JNIEnv* const env = jni::GetGeckoThreadEnv();
|
|
|
|
auto flushOnException = [=] () -> bool {
|
|
|
|
if (!env->ExceptionCheck()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (aFlags != FLUSH_FLAG_RECOVER) {
|
|
|
|
// First time seeing an exception; try flushing text.
|
|
|
|
env->ExceptionClear();
|
|
|
|
__android_log_print(ANDROID_LOG_WARN, "GeckoViewSupport",
|
|
|
|
"Recovering from IME exception");
|
|
|
|
FlushIMEText(FLUSH_FLAG_RECOVER);
|
|
|
|
} else {
|
|
|
|
// Give up because we've already tried.
|
|
|
|
MOZ_CATCH_JNI_EXCEPTION(env);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2016-01-07 02:33:18 +00:00
|
|
|
// Commit the text change and selection change transaction.
|
|
|
|
mIMETextChanges.Clear();
|
|
|
|
|
|
|
|
for (const TextRecord& record : textTransaction) {
|
|
|
|
mEditable->OnTextChange(record.text, record.start,
|
|
|
|
record.oldEnd, record.newEnd);
|
2017-01-13 19:39:27 +00:00
|
|
|
if (flushOnException()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-01-07 02:33:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mIMESelectionChanged) {
|
|
|
|
mIMESelectionChanged = false;
|
|
|
|
mEditable->OnSelectionChange(selStart, selEnd);
|
2017-01-13 19:39:27 +00:00
|
|
|
flushOnException();
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-25 16:28:53 +00:00
|
|
|
void
|
2017-01-13 19:39:27 +00:00
|
|
|
nsWindow::GeckoViewSupport::FlushIMEText(FlushChangesFlag aFlags)
|
2016-10-25 16:28:53 +00:00
|
|
|
{
|
|
|
|
// Notify Java of the newly focused content
|
|
|
|
mIMETextChanges.Clear();
|
|
|
|
mIMESelectionChanged = true;
|
|
|
|
|
|
|
|
// Use 'INT32_MAX / 2' here because subsequent text changes might combine
|
|
|
|
// with this text change, and overflow might occur if we just use
|
|
|
|
// INT32_MAX.
|
|
|
|
IMENotification notification(NOTIFY_IME_OF_TEXT_CHANGE);
|
|
|
|
notification.mTextChangeData.mStartOffset = 0;
|
|
|
|
notification.mTextChangeData.mRemovedEndOffset = INT32_MAX / 2;
|
|
|
|
notification.mTextChangeData.mAddedEndOffset = INT32_MAX / 2;
|
|
|
|
NotifyIME(notification);
|
|
|
|
|
2017-01-13 19:39:27 +00:00
|
|
|
FlushIMEChanges(aFlags);
|
2016-10-25 16:28:53 +00:00
|
|
|
}
|
|
|
|
|
2016-07-20 07:19:05 +00:00
|
|
|
static jni::ObjectArray::LocalRef
|
|
|
|
ConvertRectArrayToJavaRectFArray(JNIEnv* aJNIEnv, const nsTArray<LayoutDeviceIntRect>& aRects, const LayoutDeviceIntPoint& aOffset, const CSSToLayoutDeviceScale aScale)
|
|
|
|
{
|
|
|
|
size_t length = aRects.Length();
|
|
|
|
jobjectArray rects = aJNIEnv->NewObjectArray(length, sdk::RectF::Context().ClassRef(), nullptr);
|
|
|
|
auto rectsRef = jni::ObjectArray::LocalRef::Adopt(aJNIEnv, rects);
|
|
|
|
for (size_t i = 0; i < length; i++) {
|
|
|
|
sdk::RectF::LocalRef rect(aJNIEnv);
|
|
|
|
LayoutDeviceIntRect tmp = aRects[i] + aOffset;
|
|
|
|
sdk::RectF::New(tmp.x / aScale.scale, tmp.y / aScale.scale,
|
|
|
|
(tmp.x + tmp.width) / aScale.scale,
|
|
|
|
(tmp.y + tmp.height) / aScale.scale,
|
|
|
|
&rect);
|
|
|
|
rectsRef->SetElement(i, rect);
|
|
|
|
}
|
|
|
|
return rectsRef;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::GeckoViewSupport::UpdateCompositionRects()
|
|
|
|
{
|
|
|
|
const auto composition(window.GetIMEComposition());
|
|
|
|
if (NS_WARN_IF(!composition)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t offset = composition->NativeOffsetOfStartComposition();
|
|
|
|
WidgetQueryContentEvent textRects(true, eQueryTextRectArray, &window);
|
|
|
|
textRects.InitForQueryTextRectArray(offset, composition->String().Length());
|
|
|
|
window.DispatchEvent(&textRects);
|
|
|
|
|
|
|
|
auto rects =
|
|
|
|
ConvertRectArrayToJavaRectFArray(jni::GetGeckoThreadEnv(),
|
|
|
|
textRects.mReply.mRectArray,
|
|
|
|
window.WidgetToScreenOffset(),
|
|
|
|
window.GetDefaultScale());
|
|
|
|
|
|
|
|
mEditable->UpdateCompositionRects(rects);
|
|
|
|
}
|
|
|
|
|
2016-02-26 19:38:57 +00:00
|
|
|
void
|
|
|
|
nsWindow::GeckoViewSupport::AsyncNotifyIME(int32_t aNotification)
|
|
|
|
{
|
|
|
|
// Keep a strong reference to the window to keep 'this' alive.
|
|
|
|
RefPtr<nsWindow> window(&this->window);
|
|
|
|
|
|
|
|
nsAppShell::PostEvent([this, window, aNotification] {
|
|
|
|
if (mIMEMaskEventsCount) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mEditable->NotifyIME(aNotification);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
bool
|
2015-12-24 03:03:34 +00:00
|
|
|
nsWindow::GeckoViewSupport::NotifyIME(const IMENotification& aIMENotification)
|
2010-08-04 19:47:26 +00:00
|
|
|
{
|
2015-10-22 21:45:47 +00:00
|
|
|
MOZ_ASSERT(mEditable);
|
2015-04-17 16:29:51 +00:00
|
|
|
|
2014-02-18 00:00:15 +00:00
|
|
|
switch (aIMENotification.mMessage) {
|
2015-10-22 21:45:47 +00:00
|
|
|
case REQUEST_TO_COMMIT_COMPOSITION: {
|
|
|
|
ALOGIME("IME: REQUEST_TO_COMMIT_COMPOSITION");
|
2016-02-26 19:38:57 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
window.RemoveIMEComposition();
|
2016-02-26 19:38:57 +00:00
|
|
|
|
|
|
|
AsyncNotifyIME(GeckoEditableListener::
|
|
|
|
NOTIFY_IME_TO_COMMIT_COMPOSITION);
|
2015-10-22 21:45:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
2015-03-31 22:20:27 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
case REQUEST_TO_CANCEL_COMPOSITION: {
|
2013-03-06 06:14:34 +00:00
|
|
|
ALOGIME("IME: REQUEST_TO_CANCEL_COMPOSITION");
|
2016-10-25 16:28:54 +00:00
|
|
|
|
|
|
|
window.RemoveIMEComposition(CANCEL_IME_COMPOSITION);
|
2013-03-06 06:14:34 +00:00
|
|
|
|
2016-02-26 19:38:57 +00:00
|
|
|
AsyncNotifyIME(GeckoEditableListener::
|
|
|
|
NOTIFY_IME_TO_CANCEL_COMPOSITION);
|
2015-10-22 21:45:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
2015-03-31 22:20:27 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
case NOTIFY_IME_OF_FOCUS: {
|
2013-03-06 06:14:34 +00:00
|
|
|
ALOGIME("IME: NOTIFY_IME_OF_FOCUS");
|
2016-10-25 16:28:53 +00:00
|
|
|
// Keep a strong reference to the window to keep 'this' alive.
|
|
|
|
RefPtr<nsWindow> window(&this->window);
|
|
|
|
|
|
|
|
// Post an event because we have to flush the text before sending a
|
|
|
|
// focus event, and we may not be able to flush text during the
|
|
|
|
// NotifyIME call.
|
|
|
|
nsAppShell::PostEvent([this, window] {
|
|
|
|
--mIMEMaskEventsCount;
|
|
|
|
if (mIMEMaskEventsCount || window->Destroyed()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
FlushIMEText();
|
|
|
|
|
|
|
|
// IME will call requestCursorUpdates after getting context.
|
|
|
|
// So reset cursor update mode before getting context.
|
|
|
|
mIMEMonitorCursor = false;
|
|
|
|
|
|
|
|
MOZ_ASSERT(mEditable);
|
|
|
|
mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_OF_FOCUS);
|
|
|
|
});
|
2015-10-22 21:45:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
2015-03-31 22:20:27 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
case NOTIFY_IME_OF_BLUR: {
|
2013-03-06 06:14:34 +00:00
|
|
|
ALOGIME("IME: NOTIFY_IME_OF_BLUR");
|
|
|
|
|
2016-10-25 16:28:53 +00:00
|
|
|
if (!mIMEMaskEventsCount) {
|
|
|
|
mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_OF_BLUR);
|
|
|
|
}
|
2013-03-06 06:14:34 +00:00
|
|
|
|
2016-10-25 16:28:53 +00:00
|
|
|
// Mask events because we lost focus. Unmask on the next focus.
|
|
|
|
mIMEMaskEventsCount++;
|
2015-10-22 21:45:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
2015-03-31 22:20:27 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
case NOTIFY_IME_OF_SELECTION_CHANGE: {
|
2013-03-06 06:14:34 +00:00
|
|
|
ALOGIME("IME: NOTIFY_IME_OF_SELECTION_CHANGE");
|
|
|
|
|
|
|
|
PostFlushIMEChanges();
|
|
|
|
mIMESelectionChanged = true;
|
2015-10-22 21:45:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
2015-03-31 22:20:27 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
case NOTIFY_IME_OF_TEXT_CHANGE: {
|
|
|
|
ALOGIME("IME: NotifyIMEOfTextChange: s=%d, oe=%d, ne=%d",
|
|
|
|
aIMENotification.mTextChangeData.mStartOffset,
|
|
|
|
aIMENotification.mTextChangeData.mRemovedEndOffset,
|
|
|
|
aIMENotification.mTextChangeData.mAddedEndOffset);
|
|
|
|
|
|
|
|
/* Make sure Java's selection is up-to-date */
|
|
|
|
PostFlushIMEChanges();
|
|
|
|
mIMESelectionChanged = true;
|
|
|
|
AddIMETextChange(IMETextChange(aIMENotification));
|
|
|
|
return true;
|
|
|
|
}
|
2015-03-31 22:20:27 +00:00
|
|
|
|
2016-07-20 07:19:05 +00:00
|
|
|
case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED: {
|
|
|
|
ALOGIME("IME: NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED");
|
|
|
|
|
|
|
|
// Hardware keyboard support requires each string rect.
|
|
|
|
if (AndroidBridge::Bridge() && AndroidBridge::Bridge()->GetAPIVersion() >= 21 && mIMEMonitorCursor) {
|
|
|
|
UpdateCompositionRects();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-06 06:14:34 +00:00
|
|
|
default:
|
2015-10-22 21:45:47 +00:00
|
|
|
return false;
|
2013-03-06 06:14:34 +00:00
|
|
|
}
|
2010-08-04 19:47:26 +00:00
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
void
|
2015-12-24 03:03:34 +00:00
|
|
|
nsWindow::GeckoViewSupport::SetInputContext(const InputContext& aContext,
|
|
|
|
const InputContextAction& aAction)
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2015-10-22 21:45:47 +00:00
|
|
|
MOZ_ASSERT(mEditable);
|
2015-10-08 19:25:49 +00:00
|
|
|
|
2011-11-27 11:51:53 +00:00
|
|
|
ALOGIME("IME: SetInputContext: s=0x%X, 0x%X, action=0x%X, 0x%X",
|
|
|
|
aContext.mIMEState.mEnabled, aContext.mIMEState.mOpen,
|
|
|
|
aAction.mCause, aAction.mFocusChange);
|
2010-08-04 19:47:26 +00:00
|
|
|
|
2011-04-20 12:47:40 +00:00
|
|
|
// Ensure that opening the virtual keyboard is allowed for this specific
|
2011-11-27 11:51:52 +00:00
|
|
|
// InputContext depending on the content.ime.strict.policy pref
|
2015-07-02 20:00:44 +00:00
|
|
|
if (aContext.mIMEState.mEnabled != IMEState::DISABLED &&
|
2011-11-27 11:51:53 +00:00
|
|
|
aContext.mIMEState.mEnabled != IMEState::PLUGIN &&
|
2011-11-27 11:51:52 +00:00
|
|
|
Preferences::GetBool("content.ime.strict_policy", false) &&
|
2011-11-27 11:51:53 +00:00
|
|
|
!aAction.ContentGotFocusByTrustedCause() &&
|
|
|
|
!aAction.UserMightRequestOpenVKB()) {
|
2011-11-27 11:51:52 +00:00
|
|
|
return;
|
2011-04-20 12:47:40 +00:00
|
|
|
}
|
|
|
|
|
2013-03-05 15:24:35 +00:00
|
|
|
IMEState::Enabled enabled = aContext.mIMEState.mEnabled;
|
2012-05-24 15:03:07 +00:00
|
|
|
|
|
|
|
// Only show the virtual keyboard for plugins if mOpen is set appropriately.
|
|
|
|
// This avoids showing it whenever a plugin is focused. Bug 747492
|
|
|
|
if (aContext.mIMEState.mEnabled == IMEState::PLUGIN &&
|
|
|
|
aContext.mIMEState.mOpen != IMEState::OPEN) {
|
2013-03-05 15:24:35 +00:00
|
|
|
enabled = IMEState::DISABLED;
|
2012-05-24 15:03:07 +00:00
|
|
|
}
|
|
|
|
|
2015-06-16 23:02:39 +00:00
|
|
|
mInputContext = aContext;
|
2013-03-05 15:24:35 +00:00
|
|
|
mInputContext.mIMEState.mEnabled = enabled;
|
|
|
|
|
2013-08-14 15:32:44 +00:00
|
|
|
if (enabled == IMEState::ENABLED && aAction.UserMightRequestOpenVKB()) {
|
|
|
|
// Don't reset keyboard when we should simply open the vkb
|
2015-10-08 19:25:49 +00:00
|
|
|
mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_OPEN_VKB);
|
2013-08-14 15:32:44 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-03-05 15:24:35 +00:00
|
|
|
if (mIMEUpdatingContext) {
|
|
|
|
return;
|
|
|
|
}
|
2015-10-22 21:45:47 +00:00
|
|
|
|
|
|
|
// Keep a strong reference to the window to keep 'this' alive.
|
|
|
|
RefPtr<nsWindow> window(&this->window);
|
2013-03-05 15:24:35 +00:00
|
|
|
mIMEUpdatingContext = true;
|
2015-10-22 21:45:47 +00:00
|
|
|
|
2015-12-24 03:03:35 +00:00
|
|
|
nsAppShell::PostEvent([this, window] {
|
2015-10-22 21:45:47 +00:00
|
|
|
mIMEUpdatingContext = false;
|
|
|
|
if (window->Destroyed()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(mEditable);
|
|
|
|
mEditable->NotifyIMEContext(mInputContext.mIMEState.mEnabled,
|
|
|
|
mInputContext.mHTMLInputType,
|
|
|
|
mInputContext.mHTMLInputInputmode,
|
|
|
|
mInputContext.mActionHint);
|
|
|
|
});
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
InputContext
|
2015-12-24 03:03:34 +00:00
|
|
|
nsWindow::GeckoViewSupport::GetInputContext()
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2013-03-27 15:32:34 +00:00
|
|
|
InputContext context = mInputContext;
|
|
|
|
context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
|
|
|
|
return context;
|
2010-08-04 19:47:26 +00:00
|
|
|
}
|
|
|
|
|
2012-12-05 16:09:56 +00:00
|
|
|
void
|
2015-12-24 03:03:34 +00:00
|
|
|
nsWindow::GeckoViewSupport::OnImeSynchronize()
|
2012-12-05 16:09:56 +00:00
|
|
|
{
|
2015-10-22 21:45:47 +00:00
|
|
|
if (!mIMEMaskEventsCount) {
|
|
|
|
FlushIMEChanges();
|
2012-12-05 16:09:56 +00:00
|
|
|
}
|
2015-10-22 21:45:47 +00:00
|
|
|
mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_REPLY_EVENT);
|
2012-12-05 16:09:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
void
|
2015-12-24 03:03:34 +00:00
|
|
|
nsWindow::GeckoViewSupport::OnImeReplaceText(int32_t aStart, int32_t aEnd,
|
|
|
|
jni::String::Param aText)
|
2015-10-22 21:45:47 +00:00
|
|
|
{
|
2016-02-10 04:36:41 +00:00
|
|
|
AutoIMESynchronize as(this);
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
if (mIMEMaskEventsCount > 0) {
|
|
|
|
// Not focused; still reply to events, but don't do anything else.
|
2016-02-10 04:36:41 +00:00
|
|
|
return;
|
2015-10-22 21:45:47 +00:00
|
|
|
}
|
2012-12-05 16:09:56 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
/*
|
|
|
|
Replace text in Gecko thread from aStart to aEnd with the string text.
|
|
|
|
*/
|
|
|
|
RefPtr<nsWindow> kungFuDeathGrip(&window);
|
2016-02-09 22:27:28 +00:00
|
|
|
nsString string(aText->ToString());
|
2015-10-22 21:45:47 +00:00
|
|
|
|
|
|
|
const auto composition(window.GetIMEComposition());
|
|
|
|
MOZ_ASSERT(!composition || !composition->IsEditorHandlingEvent());
|
|
|
|
|
2016-10-25 16:28:54 +00:00
|
|
|
const bool composing = !mIMERanges->IsEmpty();
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
if (!mIMEKeyEvents.IsEmpty() || !composition ||
|
|
|
|
uint32_t(aStart) != composition->NativeOffsetOfStartComposition() ||
|
|
|
|
uint32_t(aEnd) != composition->NativeOffsetOfStartComposition() +
|
|
|
|
composition->String().Length())
|
|
|
|
{
|
|
|
|
// Only start a new composition if we have key events,
|
|
|
|
// if we don't have an existing composition, or
|
|
|
|
// the replaced text does not match our composition.
|
|
|
|
window.RemoveIMEComposition();
|
|
|
|
|
|
|
|
{
|
2016-01-30 05:08:55 +00:00
|
|
|
// Use text selection to set target postion(s) for
|
|
|
|
// insert, or replace, of text.
|
2015-10-22 21:45:47 +00:00
|
|
|
WidgetSelectionEvent event(true, eSetSelection, &window);
|
|
|
|
window.InitEvent(event, nullptr);
|
|
|
|
event.mOffset = uint32_t(aStart);
|
|
|
|
event.mLength = uint32_t(aEnd - aStart);
|
|
|
|
event.mExpandToClusterBoundary = false;
|
2016-01-30 05:08:55 +00:00
|
|
|
event.mReason = nsISelectionListener::IME_REASON;
|
2015-10-22 21:45:47 +00:00
|
|
|
window.DispatchEvent(&event);
|
2014-09-04 18:38:17 +00:00
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
if (!mIMEKeyEvents.IsEmpty()) {
|
|
|
|
nsEventStatus status;
|
|
|
|
for (uint32_t i = 0; i < mIMEKeyEvents.Length(); i++) {
|
|
|
|
const auto event = static_cast<WidgetGUIEvent*>(
|
|
|
|
mIMEKeyEvents[i].get());
|
|
|
|
if (event->mMessage == eKeyPress &&
|
|
|
|
status == nsEventStatus_eConsumeNoDefault) {
|
|
|
|
MOZ_ASSERT(i > 0 &&
|
|
|
|
mIMEKeyEvents[i - 1]->mMessage == eKeyDown);
|
|
|
|
// The previous key down event resulted in eConsumeNoDefault
|
|
|
|
// so we should not dispatch the current key press event.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// widget for duplicated events is initially nullptr.
|
2016-04-14 08:03:14 +00:00
|
|
|
event->mWidget = &window;
|
2015-10-22 21:45:47 +00:00
|
|
|
window.DispatchEvent(event, status);
|
|
|
|
}
|
|
|
|
mIMEKeyEvents.Clear();
|
2016-02-10 04:36:41 +00:00
|
|
|
return;
|
2015-10-22 21:45:47 +00:00
|
|
|
}
|
2012-12-05 16:09:56 +00:00
|
|
|
|
2016-10-25 16:28:54 +00:00
|
|
|
if (aStart != aEnd) {
|
|
|
|
// Perform a deletion first.
|
|
|
|
WidgetContentCommandEvent event(
|
|
|
|
true, eContentCommandDelete, &window);
|
|
|
|
window.InitEvent(event, nullptr);
|
|
|
|
window.DispatchEvent(&event);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start a composition if we're not just performing a deletion.
|
|
|
|
if (composing || !string.IsEmpty()) {
|
2015-10-22 21:45:47 +00:00
|
|
|
WidgetCompositionEvent event(true, eCompositionStart, &window);
|
|
|
|
window.InitEvent(event, nullptr);
|
|
|
|
window.DispatchEvent(&event);
|
2014-09-04 18:38:17 +00:00
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
} else if (composition->String().Equals(string)) {
|
|
|
|
/* If the new text is the same as the existing composition text,
|
|
|
|
* the NS_COMPOSITION_CHANGE event does not generate a text
|
|
|
|
* change notification. However, the Java side still expects
|
|
|
|
* one, so we manually generate a notification. */
|
|
|
|
IMETextChange dummyChange;
|
|
|
|
dummyChange.mStart = aStart;
|
|
|
|
dummyChange.mOldEnd = dummyChange.mNewEnd = aEnd;
|
|
|
|
AddIMETextChange(dummyChange);
|
2012-12-05 16:09:56 +00:00
|
|
|
}
|
|
|
|
|
2016-10-25 16:28:54 +00:00
|
|
|
// Check composition again because previous events may have destroyed our
|
|
|
|
// composition; in which case we should just skip the next event.
|
2015-10-22 21:45:47 +00:00
|
|
|
if (window.GetIMEComposition()) {
|
|
|
|
WidgetCompositionEvent event(true, eCompositionChange, &window);
|
|
|
|
window.InitEvent(event, nullptr);
|
|
|
|
event.mData = string;
|
2013-01-09 16:57:48 +00:00
|
|
|
|
2015-11-03 16:53:58 +00:00
|
|
|
if (composing) {
|
|
|
|
event.mRanges = new TextRangeArray();
|
|
|
|
mIMERanges.swap(event.mRanges);
|
2016-10-25 16:28:54 +00:00
|
|
|
} else {
|
|
|
|
event.mMessage = eCompositionCommit;
|
2015-11-03 16:53:58 +00:00
|
|
|
}
|
2013-01-09 16:57:48 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
window.DispatchEvent(&event);
|
2015-11-03 16:53:58 +00:00
|
|
|
|
|
|
|
} else if (composing) {
|
|
|
|
// Ensure IME ranges are empty.
|
|
|
|
mIMERanges->Clear();
|
2015-10-22 21:45:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mInputContext.mMayBeIMEUnaware) {
|
|
|
|
SendIMEDummyKeyEvents();
|
|
|
|
}
|
2012-12-05 16:09:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
void
|
2015-12-24 03:03:34 +00:00
|
|
|
nsWindow::GeckoViewSupport::OnImeAddCompositionRange(
|
2015-10-22 21:45:47 +00:00
|
|
|
int32_t aStart, int32_t aEnd, int32_t aRangeType, int32_t aRangeStyle,
|
|
|
|
int32_t aRangeLineStyle, bool aRangeBoldLine, int32_t aRangeForeColor,
|
|
|
|
int32_t aRangeBackColor, int32_t aRangeLineColor)
|
|
|
|
{
|
|
|
|
if (mIMEMaskEventsCount > 0) {
|
|
|
|
// Not focused.
|
|
|
|
return;
|
2012-12-05 16:09:56 +00:00
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
TextRange range;
|
|
|
|
range.mStartOffset = aStart;
|
|
|
|
range.mEndOffset = aEnd;
|
2016-06-04 00:49:21 +00:00
|
|
|
range.mRangeType = ToTextRangeType(aRangeType);
|
2015-10-22 21:45:47 +00:00
|
|
|
range.mRangeStyle.mDefinedStyles = aRangeStyle;
|
|
|
|
range.mRangeStyle.mLineStyle = aRangeLineStyle;
|
|
|
|
range.mRangeStyle.mIsBoldLine = aRangeBoldLine;
|
|
|
|
range.mRangeStyle.mForegroundColor =
|
|
|
|
ConvertAndroidColor(uint32_t(aRangeForeColor));
|
|
|
|
range.mRangeStyle.mBackgroundColor =
|
|
|
|
ConvertAndroidColor(uint32_t(aRangeBackColor));
|
|
|
|
range.mRangeStyle.mUnderlineColor =
|
|
|
|
ConvertAndroidColor(uint32_t(aRangeLineColor));
|
|
|
|
mIMERanges->AppendElement(range);
|
|
|
|
}
|
2012-12-05 16:09:56 +00:00
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
void
|
2015-12-24 03:03:34 +00:00
|
|
|
nsWindow::GeckoViewSupport::OnImeUpdateComposition(int32_t aStart, int32_t aEnd)
|
2015-10-22 21:45:47 +00:00
|
|
|
{
|
|
|
|
if (mIMEMaskEventsCount > 0) {
|
|
|
|
// Not focused.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-02-26 19:38:57 +00:00
|
|
|
RefPtr<nsWindow> kungFuDeathGrip(&window);
|
|
|
|
|
2015-11-03 16:53:58 +00:00
|
|
|
// A composition with no ranges means we want to set the selection.
|
|
|
|
if (mIMERanges->IsEmpty()) {
|
|
|
|
MOZ_ASSERT(aStart >= 0 && aEnd >= 0);
|
|
|
|
window.RemoveIMEComposition();
|
|
|
|
|
|
|
|
WidgetSelectionEvent selEvent(true, eSetSelection, &window);
|
|
|
|
window.InitEvent(selEvent, nullptr);
|
|
|
|
|
|
|
|
selEvent.mOffset = std::min(aStart, aEnd);
|
|
|
|
selEvent.mLength = std::max(aStart, aEnd) - selEvent.mOffset;
|
|
|
|
selEvent.mReversed = aStart > aEnd;
|
|
|
|
selEvent.mExpandToClusterBoundary = false;
|
|
|
|
|
|
|
|
window.DispatchEvent(&selEvent);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
/*
|
|
|
|
Update the composition from aStart to aEnd using
|
|
|
|
information from added ranges. This is only used for
|
|
|
|
visual indication and does not affect the text content.
|
|
|
|
Only the offsets are specified and not the text content
|
|
|
|
to eliminate the possibility of this event altering the
|
|
|
|
text content unintentionally.
|
|
|
|
*/
|
|
|
|
const auto composition(window.GetIMEComposition());
|
|
|
|
MOZ_ASSERT(!composition || !composition->IsEditorHandlingEvent());
|
|
|
|
|
|
|
|
WidgetCompositionEvent event(true, eCompositionChange, &window);
|
|
|
|
window.InitEvent(event, nullptr);
|
|
|
|
|
|
|
|
event.mRanges = new TextRangeArray();
|
|
|
|
mIMERanges.swap(event.mRanges);
|
|
|
|
|
|
|
|
if (!composition ||
|
|
|
|
uint32_t(aStart) != composition->NativeOffsetOfStartComposition() ||
|
|
|
|
uint32_t(aEnd) != composition->NativeOffsetOfStartComposition() +
|
|
|
|
composition->String().Length())
|
|
|
|
{
|
|
|
|
// Only start new composition if we don't have an existing one,
|
|
|
|
// or if the existing composition doesn't match the new one.
|
|
|
|
window.RemoveIMEComposition();
|
|
|
|
|
|
|
|
{
|
|
|
|
WidgetSelectionEvent event(true, eSetSelection, &window);
|
|
|
|
window.InitEvent(event, nullptr);
|
|
|
|
event.mOffset = uint32_t(aStart);
|
|
|
|
event.mLength = uint32_t(aEnd - aStart);
|
|
|
|
event.mExpandToClusterBoundary = false;
|
2015-12-01 20:25:06 +00:00
|
|
|
event.mReason = nsISelectionListener::IME_REASON;
|
2015-10-22 21:45:47 +00:00
|
|
|
window.DispatchEvent(&event);
|
2012-12-05 16:09:56 +00:00
|
|
|
}
|
2015-10-22 21:45:47 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
WidgetQueryContentEvent queryEvent(true, eQuerySelectedText,
|
|
|
|
&window);
|
|
|
|
window.InitEvent(queryEvent, nullptr);
|
|
|
|
window.DispatchEvent(&queryEvent);
|
|
|
|
MOZ_ASSERT(queryEvent.mSucceeded);
|
|
|
|
event.mData = queryEvent.mReply.mString;
|
2012-12-05 16:09:56 +00:00
|
|
|
}
|
2015-10-22 21:45:47 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
WidgetCompositionEvent event(true, eCompositionStart, &window);
|
|
|
|
window.InitEvent(event, nullptr);
|
|
|
|
window.DispatchEvent(&event);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// If the new composition matches the existing composition,
|
|
|
|
// reuse the old composition.
|
|
|
|
event.mData = composition->String();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_ANDROID_IME
|
|
|
|
const NS_ConvertUTF16toUTF8 data(event.mData);
|
|
|
|
const char* text = data.get();
|
|
|
|
ALOGIME("IME: IME_SET_TEXT: text=\"%s\", length=%u, range=%u",
|
|
|
|
text, event.mData.Length(), event.mRanges->Length());
|
|
|
|
#endif // DEBUG_ANDROID_IME
|
|
|
|
|
|
|
|
// Previous events may have destroyed our composition; bail in that case.
|
|
|
|
if (window.GetIMEComposition()) {
|
|
|
|
window.DispatchEvent(&event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-20 07:19:05 +00:00
|
|
|
void
|
|
|
|
nsWindow::GeckoViewSupport::OnImeRequestCursorUpdates(int aRequestMode)
|
|
|
|
{
|
|
|
|
if (aRequestMode == IME_MONITOR_CURSOR_ONE_SHOT) {
|
|
|
|
UpdateCompositionRects();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mIMEMonitorCursor = (aRequestMode == IME_MONITOR_CURSOR_START_MONITOR);
|
|
|
|
}
|
|
|
|
|
2015-10-22 21:45:47 +00:00
|
|
|
void
|
|
|
|
nsWindow::UserActivity()
|
|
|
|
{
|
|
|
|
if (!mIdleService) {
|
|
|
|
mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mIdleService) {
|
|
|
|
mIdleService->ResetIdleTimeOut(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(this == FindTopLevel());
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
if (!mGeckoViewSupport) {
|
2015-10-22 21:45:47 +00:00
|
|
|
// Non-GeckoView windows don't support IME operations.
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
if (mGeckoViewSupport->NotifyIME(aIMENotification)) {
|
2015-10-22 21:45:47 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2016-12-21 04:27:20 +00:00
|
|
|
void
|
2015-10-22 21:45:47 +00:00
|
|
|
nsWindow::SetInputContext(const InputContext& aContext,
|
|
|
|
const InputContextAction& aAction)
|
|
|
|
{
|
|
|
|
nsWindow* top = FindTopLevel();
|
|
|
|
MOZ_ASSERT(top);
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
if (!top->mGeckoViewSupport) {
|
2015-10-22 21:45:47 +00:00
|
|
|
// Non-GeckoView windows don't support IME operations.
|
|
|
|
return;
|
2012-12-05 16:09:56 +00:00
|
|
|
}
|
2015-10-22 21:45:47 +00:00
|
|
|
|
|
|
|
// We are using an IME event later to notify Java, and the IME event
|
|
|
|
// will be processed by the top window. Therefore, to ensure the
|
|
|
|
// IME event uses the correct mInputContext, we need to let the top
|
|
|
|
// window process SetInputContext
|
2015-12-24 03:03:34 +00:00
|
|
|
top->mGeckoViewSupport->SetInputContext(aContext, aAction);
|
2015-10-22 21:45:47 +00:00
|
|
|
}
|
|
|
|
|
2016-12-21 04:27:20 +00:00
|
|
|
InputContext
|
2015-10-22 21:45:47 +00:00
|
|
|
nsWindow::GetInputContext()
|
|
|
|
{
|
|
|
|
nsWindow* top = FindTopLevel();
|
|
|
|
MOZ_ASSERT(top);
|
|
|
|
|
2015-12-24 03:03:34 +00:00
|
|
|
if (!top->mGeckoViewSupport) {
|
2015-10-22 21:45:47 +00:00
|
|
|
// Non-GeckoView windows don't support IME operations.
|
|
|
|
return InputContext();
|
|
|
|
}
|
|
|
|
|
|
|
|
// We let the top window process SetInputContext,
|
|
|
|
// so we should let it process GetInputContext as well.
|
2015-12-24 03:03:34 +00:00
|
|
|
return top->mGeckoViewSupport->GetInputContext();
|
2010-08-04 19:47:26 +00:00
|
|
|
}
|
|
|
|
|
2010-09-24 03:28:15 +00:00
|
|
|
nsIMEUpdatePreference
|
|
|
|
nsWindow::GetIMEUpdatePreference()
|
|
|
|
{
|
2015-10-10 01:21:02 +00:00
|
|
|
// While a plugin has focus, nsWindow for Android doesn't need any
|
|
|
|
// notifications.
|
2015-10-22 21:45:47 +00:00
|
|
|
if (GetInputContext().mIMEState.mEnabled == IMEState::PLUGIN) {
|
2015-10-10 01:21:02 +00:00
|
|
|
return nsIMEUpdatePreference();
|
|
|
|
}
|
2016-06-28 06:23:12 +00:00
|
|
|
return nsIMEUpdatePreference(nsIMEUpdatePreference::NOTIFY_TEXT_CHANGE);
|
2010-09-24 03:28:15 +00:00
|
|
|
}
|
|
|
|
|
2016-02-23 15:17:46 +00:00
|
|
|
nsresult
|
|
|
|
nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId,
|
|
|
|
TouchPointerState aPointerState,
|
2016-04-15 10:39:36 +00:00
|
|
|
LayoutDeviceIntPoint aPoint,
|
2016-02-23 15:17:46 +00:00
|
|
|
double aPointerPressure,
|
|
|
|
uint32_t aPointerOrientation,
|
|
|
|
nsIObserver* aObserver)
|
|
|
|
{
|
|
|
|
mozilla::widget::AutoObserverNotifier notifier(aObserver, "touchpoint");
|
|
|
|
|
|
|
|
int eventType;
|
|
|
|
switch (aPointerState) {
|
|
|
|
case TOUCH_CONTACT:
|
|
|
|
// This could be a ACTION_DOWN or ACTION_MOVE depending on the
|
|
|
|
// existing state; it is mapped to the right thing in Java.
|
|
|
|
eventType = sdk::MotionEvent::ACTION_POINTER_DOWN;
|
|
|
|
break;
|
|
|
|
case TOUCH_REMOVE:
|
|
|
|
// This could be turned into a ACTION_UP in Java
|
|
|
|
eventType = sdk::MotionEvent::ACTION_POINTER_UP;
|
|
|
|
break;
|
|
|
|
case TOUCH_CANCEL:
|
|
|
|
eventType = sdk::MotionEvent::ACTION_CANCEL;
|
|
|
|
break;
|
|
|
|
case TOUCH_HOVER: // not supported for now
|
|
|
|
default:
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
2016-08-01 18:21:31 +00:00
|
|
|
MOZ_ASSERT(mLayerViewSupport);
|
|
|
|
GeckoLayerClient::LocalRef client = mLayerViewSupport->GetLayerClient();
|
2016-02-23 15:17:46 +00:00
|
|
|
client->SynthesizeNativeTouchPoint(aPointerId, eventType,
|
2016-04-15 10:39:36 +00:00
|
|
|
aPoint.x, aPoint.y, aPointerPressure, aPointerOrientation);
|
2016-02-23 15:17:46 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-05-16 16:17:17 +00:00
|
|
|
nsresult
|
|
|
|
nsWindow::SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
|
|
|
|
uint32_t aNativeMessage,
|
|
|
|
uint32_t aModifierFlags,
|
|
|
|
nsIObserver* aObserver)
|
|
|
|
{
|
|
|
|
mozilla::widget::AutoObserverNotifier notifier(aObserver, "mouseevent");
|
|
|
|
|
2016-08-01 18:21:31 +00:00
|
|
|
MOZ_ASSERT(mLayerViewSupport);
|
|
|
|
GeckoLayerClient::LocalRef client = mLayerViewSupport->GetLayerClient();
|
2016-05-16 16:17:17 +00:00
|
|
|
client->SynthesizeNativeMouseEvent(aNativeMessage, aPoint.x, aPoint.y);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsWindow::SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
|
|
|
|
nsIObserver* aObserver)
|
|
|
|
{
|
|
|
|
mozilla::widget::AutoObserverNotifier notifier(aObserver, "mouseevent");
|
|
|
|
|
2016-08-01 18:21:31 +00:00
|
|
|
MOZ_ASSERT(mLayerViewSupport);
|
|
|
|
GeckoLayerClient::LocalRef client = mLayerViewSupport->GetLayerClient();
|
2016-05-16 16:17:17 +00:00
|
|
|
client->SynthesizeNativeMouseEvent(sdk::MotionEvent::ACTION_HOVER_MOVE, aPoint.x, aPoint.y);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2016-02-23 15:17:46 +00:00
|
|
|
|
2016-09-01 16:24:39 +00:00
|
|
|
bool
|
2016-11-08 02:16:52 +00:00
|
|
|
nsWindow::PreRender(WidgetRenderingContext* aContext)
|
2016-09-01 16:24:39 +00:00
|
|
|
{
|
|
|
|
if (Destroyed()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-11-08 02:16:52 +00:00
|
|
|
layers::Compositor* compositor = aContext->mCompositor;
|
2016-09-01 16:24:39 +00:00
|
|
|
|
|
|
|
GeckoLayerClient::LocalRef client;
|
|
|
|
|
|
|
|
if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
|
|
|
|
client = lvs->GetLayerClient();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (compositor && client) {
|
|
|
|
// Android Color is ARGB which is apparently unusual.
|
|
|
|
compositor->SetDefaultClearColor(gfx::Color::UnusualFromARGB((uint32_t)client->ClearColor()));
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2012-02-10 03:47:50 +00:00
|
|
|
void
|
2016-11-08 02:16:52 +00:00
|
|
|
nsWindow::DrawWindowUnderlay(WidgetRenderingContext* aContext,
|
2015-11-17 04:34:00 +00:00
|
|
|
LayoutDeviceIntRect aRect)
|
2012-05-04 15:08:47 +00:00
|
|
|
{
|
2016-01-14 23:20:02 +00:00
|
|
|
if (Destroyed()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-08-18 22:03:04 +00:00
|
|
|
|
|
|
|
GeckoLayerClient::LocalRef client;
|
|
|
|
|
|
|
|
if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
|
|
|
|
client = lvs->GetLayerClient();
|
|
|
|
}
|
2013-11-12 18:41:01 +00:00
|
|
|
|
2016-09-01 16:24:39 +00:00
|
|
|
if (!client) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-12-24 03:03:33 +00:00
|
|
|
LayerRenderer::Frame::LocalRef frame = client->CreateFrame();
|
|
|
|
mLayerRendererFrame = frame;
|
|
|
|
if (NS_WARN_IF(!mLayerRendererFrame)) {
|
2013-11-12 18:41:01 +00:00
|
|
|
return;
|
2013-11-12 18:41:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!WidgetPaintsBackground()) {
|
|
|
|
return;
|
|
|
|
}
|
2013-11-12 18:41:01 +00:00
|
|
|
|
2015-12-24 03:03:33 +00:00
|
|
|
frame->BeginDrawing();
|
2012-02-10 03:47:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-11-08 02:16:52 +00:00
|
|
|
nsWindow::DrawWindowOverlay(WidgetRenderingContext* aContext,
|
2015-11-19 03:10:38 +00:00
|
|
|
LayoutDeviceIntRect aRect)
|
2012-05-04 15:08:47 +00:00
|
|
|
{
|
2014-05-23 21:12:29 +00:00
|
|
|
PROFILER_LABEL("nsWindow", "DrawWindowOverlay",
|
|
|
|
js::ProfileEntry::Category::GRAPHICS);
|
|
|
|
|
2016-01-14 23:20:02 +00:00
|
|
|
if (Destroyed() || NS_WARN_IF(!mLayerRendererFrame)) {
|
2014-04-03 15:01:07 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-02-11 07:03:02 +00:00
|
|
|
|
2015-12-24 03:03:33 +00:00
|
|
|
mLayerRendererFrame->EndDrawing();
|
|
|
|
mLayerRendererFrame = nullptr;
|
2012-02-10 03:47:50 +00:00
|
|
|
}
|
2012-03-14 04:15:11 +00:00
|
|
|
|
2012-08-29 05:48:43 +00:00
|
|
|
bool
|
|
|
|
nsWindow::WidgetPaintsBackground()
|
|
|
|
{
|
|
|
|
static bool sWidgetPaintsBackground = true;
|
|
|
|
static bool sWidgetPaintsBackgroundPrefCached = false;
|
|
|
|
|
|
|
|
if (!sWidgetPaintsBackgroundPrefCached) {
|
|
|
|
sWidgetPaintsBackgroundPrefCached = true;
|
|
|
|
mozilla::Preferences::AddBoolVarCache(&sWidgetPaintsBackground,
|
|
|
|
"android.widget_paints_background",
|
|
|
|
true);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sWidgetPaintsBackground;
|
|
|
|
}
|
|
|
|
|
2012-08-13 10:10:10 +00:00
|
|
|
bool
|
|
|
|
nsWindow::NeedsPaint()
|
|
|
|
{
|
2016-08-01 18:21:31 +00:00
|
|
|
if (!mLayerViewSupport || mLayerViewSupport->CompositorPaused() ||
|
2015-12-24 03:03:34 +00:00
|
|
|
// FindTopLevel() != nsWindow::TopWindow() ||
|
|
|
|
!GetLayerManager(nullptr)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return nsIWidget::NeedsPaint();
|
2012-08-13 10:10:10 +00:00
|
|
|
}
|
|
|
|
|
2015-04-20 20:16:17 +00:00
|
|
|
void
|
|
|
|
nsWindow::ConfigureAPZControllerThread()
|
|
|
|
{
|
2016-11-30 22:59:57 +00:00
|
|
|
APZThreadUtils::SetControllerThread(mozilla::GetAndroidUiThreadMessageLoop());
|
2015-04-20 20:16:17 +00:00
|
|
|
}
|
|
|
|
|
2014-12-15 09:49:51 +00:00
|
|
|
already_AddRefed<GeckoContentController>
|
|
|
|
nsWindow::CreateRootContentController()
|
|
|
|
{
|
2016-01-15 18:05:45 +00:00
|
|
|
RefPtr<GeckoContentController> controller = new AndroidContentController(this, mAPZEventState, mAPZC);
|
2014-12-15 09:49:51 +00:00
|
|
|
return controller.forget();
|
2013-07-30 18:03:43 +00:00
|
|
|
}
|
|
|
|
|
2015-04-24 09:43:31 +00:00
|
|
|
uint32_t
|
|
|
|
nsWindow::GetMaxTouchPoints() const
|
|
|
|
{
|
|
|
|
return GeckoAppShell::GetMaxTouchPoints();
|
|
|
|
}
|
2015-09-03 14:30:41 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
nsWindow::UpdateZoomConstraints(const uint32_t& aPresShellId,
|
|
|
|
const FrameMetrics::ViewID& aViewId,
|
|
|
|
const mozilla::Maybe<ZoomConstraints>& aConstraints)
|
|
|
|
{
|
|
|
|
nsBaseWidget::UpdateZoomConstraints(aPresShellId, aViewId, aConstraints);
|
|
|
|
}
|
2016-05-18 05:33:22 +00:00
|
|
|
|
2017-01-05 19:11:41 +00:00
|
|
|
CompositorBridgeChild*
|
|
|
|
nsWindow::GetCompositorBridgeChild() const
|
2016-05-18 05:33:22 +00:00
|
|
|
{
|
2017-01-05 19:11:41 +00:00
|
|
|
return mCompositorSession ? mCompositorSession->GetCompositorBridgeChild() : nullptr;
|
2016-09-29 06:23:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<nsIScreen>
|
|
|
|
nsWindow::GetWidgetScreen()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIScreenManager> screenMgr =
|
|
|
|
do_GetService("@mozilla.org/gfx/screenmanager;1");
|
|
|
|
MOZ_ASSERT(screenMgr, "Failed to get nsIScreenManager");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIScreen> screen;
|
|
|
|
screenMgr->ScreenForId(mScreenId, getter_AddRefs(screen));
|
|
|
|
|
|
|
|
return screen.forget();
|
2016-05-18 05:33:22 +00:00
|
|
|
}
|
2016-10-03 16:26:00 +00:00
|
|
|
|
|
|
|
jni::DependentRef<java::GeckoLayerClient>
|
|
|
|
nsWindow::GetLayerClient()
|
|
|
|
{
|
|
|
|
if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
|
|
|
|
return lvs->GetLayerClient().Get();
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|