summaryrefslogtreecommitdiffstats
path: root/widget/android/nsWindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'widget/android/nsWindow.cpp')
-rw-r--r--widget/android/nsWindow.cpp3638
1 files changed, 0 insertions, 3638 deletions
diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp
deleted file mode 100644
index 9423a4a26..000000000
--- a/widget/android/nsWindow.cpp
+++ /dev/null
@@ -1,3638 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
- * vim: set sw=4 ts=4 expandtab:
- * 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/. */
-
-#include <android/log.h>
-#include <android/native_window.h>
-#include <android/native_window_jni.h>
-#include <math.h>
-#include <unistd.h>
-
-#include "mozilla/IMEStateManager.h"
-#include "mozilla/MiscEvents.h"
-#include "mozilla/MouseEvents.h"
-#include "mozilla/TextComposition.h"
-#include "mozilla/TextEvents.h"
-#include "mozilla/TouchEvents.h"
-#include "mozilla/TypeTraits.h"
-#include "mozilla/WeakPtr.h"
-
-#include "mozilla/dom/ContentParent.h"
-#include "mozilla/dom/ContentChild.h"
-#include "mozilla/Unused.h"
-#include "mozilla/Preferences.h"
-#include "mozilla/layers/RenderTrace.h"
-#include <algorithm>
-
-using mozilla::dom::ContentParent;
-using mozilla::dom::ContentChild;
-using mozilla::Unused;
-
-#include "nsWindow.h"
-
-#include "nsIBaseWindow.h"
-#include "nsIDOMChromeWindow.h"
-#include "nsIObserverService.h"
-#include "nsISelection.h"
-#include "nsISupportsPrimitives.h"
-#include "nsIWidgetListener.h"
-#include "nsIWindowWatcher.h"
-#include "nsIXULWindow.h"
-
-#include "nsAppShell.h"
-#include "nsFocusManager.h"
-#include "nsIdleService.h"
-#include "nsLayoutUtils.h"
-#include "nsViewManager.h"
-
-#include "WidgetUtils.h"
-
-#include "nsIDOMSimpleGestureEvent.h"
-
-#include "nsGkAtoms.h"
-#include "nsWidgetsCID.h"
-#include "nsGfxCIID.h"
-
-#include "gfxContext.h"
-
-#include "Layers.h"
-#include "mozilla/layers/LayerManagerComposite.h"
-#include "mozilla/layers/AsyncCompositionManager.h"
-#include "mozilla/layers/APZEventState.h"
-#include "mozilla/layers/APZThreadUtils.h"
-#include "mozilla/layers/IAPZCTreeManager.h"
-#include "GLContext.h"
-#include "GLContextProvider.h"
-#include "ScopedGLHelpers.h"
-#include "mozilla/layers/CompositorOGL.h"
-#include "AndroidContentController.h"
-
-#include "nsTArray.h"
-
-#include "AndroidBridge.h"
-#include "AndroidBridgeUtilities.h"
-#include "android_npapi.h"
-#include "FennecJNINatives.h"
-#include "GeneratedJNINatives.h"
-#include "KeyEvent.h"
-#include "MotionEvent.h"
-
-#include "imgIEncoder.h"
-
-#include "nsString.h"
-#include "GeckoProfiler.h" // For PROFILER_LABEL
-#include "nsIXULRuntime.h"
-#include "nsPrintfCString.h"
-
-using namespace mozilla;
-using namespace mozilla::dom;
-using namespace mozilla::layers;
-using namespace mozilla::java;
-using namespace mozilla::widget;
-
-NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
-
-#include "mozilla/layers/CompositorBridgeChild.h"
-#include "mozilla/layers/CompositorBridgeParent.h"
-#include "mozilla/layers/CompositorSession.h"
-#include "mozilla/layers/LayerTransactionParent.h"
-#include "mozilla/Services.h"
-#include "nsThreadUtils.h"
-
-// All the toplevel windows that have been created; these are in
-// stacking order, so the window at gTopLevelWindows[0] is the topmost
-// one.
-static nsTArray<nsWindow*> gTopLevelWindows;
-
-static bool sFailedToCreateGLContext = false;
-
-// Multitouch swipe thresholds in inches
-static const double SWIPE_MAX_PINCH_DELTA_INCHES = 0.4;
-static const double SWIPE_MIN_DISTANCE_INCHES = 0.6;
-
-// 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;
-
-static Modifiers GetModifiers(int32_t metaState);
-
-template<typename Lambda, bool IsStatic, typename InstanceType, class Impl>
-class nsWindow::WindowEvent : public nsAppShell::LambdaEvent<Lambda>
-{
- typedef nsAppShell::Event Event;
- typedef nsAppShell::LambdaEvent<Lambda> Base;
-
- bool IsStaleCall()
- {
- if (IsStatic) {
- // Static calls are never stale.
- return false;
- }
-
- JNIEnv* const env = mozilla::jni::GetEnvForThread();
-
- const auto natives = reinterpret_cast<mozilla::WeakPtr<Impl>*>(
- jni::GetNativeHandle(env, mInstance.Get()));
- MOZ_CATCH_JNI_EXCEPTION(env);
-
- // 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();
- }
-
- const InstanceType mInstance;
- const Event::Type mEventType;
-
-public:
- WindowEvent(Lambda&& aLambda,
- InstanceType&& aInstance,
- Event::Type aEventType = Event::Type::kGeneralActivity)
- : Base(mozilla::Move(aLambda))
- , mInstance(mozilla::Move(aInstance))
- , mEventType(aEventType)
- {}
-
- WindowEvent(Lambda&& aLambda,
- Event::Type aEventType = Event::Type::kGeneralActivity)
- : Base(mozilla::Move(aLambda))
- , mInstance(Base::lambda.GetThisArg())
- , mEventType(aEventType)
- {}
-
- void Run() override
- {
- if (!IsStaleCall()) {
- return Base::Run();
- }
- }
-
- Event::Type ActivityType() const override
- {
- return mEventType;
- }
-};
-
-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*(); }
-};
-
-
-class nsWindow::GeckoViewSupport final
- : public GeckoView::Window::Natives<GeckoViewSupport>
- , public GeckoEditable::Natives<GeckoViewSupport>
- , public SupportsWeakPtr<GeckoViewSupport>
-{
- nsWindow& window;
-
-public:
- typedef GeckoView::Window::Natives<GeckoViewSupport> Base;
- typedef GeckoEditable::Natives<GeckoViewSupport> EditableBase;
-
- MOZ_DECLARE_WEAKREFERENCE_TYPENAME(GeckoViewSupport);
-
- template<typename Functor>
- static void OnNativeCall(Functor&& aCall)
- {
- if (aCall.IsTarget(&Open) && NS_IsMainThread()) {
- // 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.
- return aCall();
- }
-
- 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));
- }
-
- GeckoViewSupport(nsWindow* aWindow,
- const GeckoView::Window::LocalRef& aInstance,
- GeckoView::Param aView)
- : window(*aWindow)
- , mEditable(GeckoEditable::New(aView))
- , mIMERanges(new TextRangeArray())
- , mIMEMaskEventsCount(1) // Mask IME events since there's no focus yet
- , mIMEUpdatingContext(false)
- , mIMESelectionChanged(false)
- , mIMETextChangedDuringFlush(false)
- , mIMEMonitorCursor(false)
- {
- Base::AttachNative(aInstance, this);
- EditableBase::AttachNative(mEditable, this);
- }
-
- ~GeckoViewSupport();
-
- using Base::DisposeNative;
- using EditableBase::DisposeNative;
-
- /**
- * GeckoView methods
- */
-private:
- nsCOMPtr<nsPIDOMWindowOuter> mDOMWindow;
-
-public:
- // Create and attach a window.
- static void Open(const jni::Class::LocalRef& aCls,
- GeckoView::Window::Param aWindow,
- GeckoView::Param aView, jni::Object::Param aCompositor,
- jni::String::Param aChromeURI,
- int32_t screenId);
-
- // Close and destroy the nsWindow.
- void Close();
-
- // Reattach this nsWindow to a new GeckoView.
- void Reattach(const GeckoView::Window::LocalRef& inst,
- GeckoView::Param aView, jni::Object::Param aCompositor);
-
- void LoadUri(jni::String::Param aUri, int32_t aFlags);
-
- /**
- * GeckoEditable methods
- */
-private:
- /*
- Rules for managing IME between Gecko and Java:
-
- * Gecko controls the text content, and Java shadows the Gecko text
- through text updates
- * Gecko and Java maintain separate selections, and synchronize when
- needed through selection updates and set-selection events
- * 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)
- {
- MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE,
- "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;
- java::GeckoEditable::GlobalRef mEditable;
- AutoTArray<mozilla::UniquePtr<mozilla::WidgetEvent>, 8> mIMEKeyEvents;
- AutoTArray<IMETextChange, 4> mIMETextChanges;
- InputContext mInputContext;
- RefPtr<mozilla::TextRangeArray> mIMERanges;
- int32_t mIMEMaskEventsCount; // Mask events when > 0.
- bool mIMEUpdatingContext;
- bool mIMESelectionChanged;
- bool mIMETextChangedDuringFlush;
- bool mIMEMonitorCursor;
-
- void SendIMEDummyKeyEvents();
- void AddIMETextChange(const IMETextChange& aChange);
-
- enum FlushChangesFlag {
- // Not retrying.
- FLUSH_FLAG_NONE,
- // Retrying due to IME text changes during flush.
- FLUSH_FLAG_RETRY,
- // Retrying due to IME sync exceptions during flush.
- FLUSH_FLAG_RECOVER
- };
- void PostFlushIMEChanges();
- void FlushIMEChanges(FlushChangesFlag aFlags = FLUSH_FLAG_NONE);
- void FlushIMEText(FlushChangesFlag aFlags = FLUSH_FLAG_NONE);
- void AsyncNotifyIME(int32_t aNotification);
- void UpdateCompositionRects();
-
-public:
- bool NotifyIME(const IMENotification& aIMENotification);
- void SetInputContext(const InputContext& aContext,
- const InputContextAction& aAction);
- InputContext GetInputContext();
-
- // 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(); }
- };
-
- // Handle an Android KeyEvent.
- 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,
- bool aIsSynthesizedImeKey, jni::Object::Param originalEvent);
-
- // Synchronize Gecko thread with the InputConnection thread.
- void OnImeSynchronize();
-
- // Replace a range of text with new text.
- void OnImeReplaceText(int32_t aStart, int32_t aEnd,
- jni::String::Param aText);
-
- // Add styling for a range within the active composition.
- 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);
-
- // Update styling for the active composition using previous-added ranges.
- void OnImeUpdateComposition(int32_t aStart, int32_t aEnd);
-
- // Set cursor mode whether IME requests
- void OnImeRequestCursorUpdates(int aRequestMode);
-};
-
-/**
- * NativePanZoomController handles its native calls on the UI thread, so make
- * it separate from GeckoViewSupport.
- */
-class nsWindow::NPZCSupport final
- : public NativePanZoomController::Natives<NPZCSupport>
-{
- using LockedWindowPtr = WindowPtr<NPZCSupport>::Locked;
-
- WindowPtr<NPZCSupport> mWindow;
- NativePanZoomController::GlobalRef mNPZC;
- int mPreviousButtons;
-
-public:
- typedef NativePanZoomController::Natives<NPZCSupport> Base;
-
- NPZCSupport(NativePtr<NPZCSupport>* aPtr, nsWindow* aWindow,
- const NativePanZoomController::LocalRef& aNPZC)
- : mWindow(aPtr, aWindow)
- , mNPZC(aNPZC)
- , mPreviousButtons(0)
- {}
-
- ~NPZCSupport()
- {}
-
- using Base::AttachNative;
- using Base::DisposeNative;
-
- void OnDetach()
- {
- // There are several considerations when shutting down NPZC. 1) The
- // Gecko thread may destroy NPZC at any time when nsWindow closes. 2)
- // There may be pending events on the Gecko thread when NPZC is
- // destroyed. 3) mWindow may not be available when the pending event
- // runs. 4) The UI thread may destroy NPZC at any time when GeckoView
- // is destroyed. 5) The UI thread may destroy NPZC at the same time as
- // Gecko thread trying to destroy NPZC. 6) There may be pending calls
- // on the UI thread when NPZC is destroyed. 7) mWindow may have been
- // cleared on the Gecko thread when the pending call happens on the UI
- // thread.
- //
- // 1) happens through OnDetach, which first notifies the UI
- // thread through Destroy; Destroy then calls DisposeNative, which
- // finally disposes the native instance back on the Gecko thread. Using
- // Destroy to indirectly call DisposeNative here also solves 5), by
- // making everything go through the UI thread, avoiding contention.
- //
- // 2) and 3) are solved by clearing mWindow, which signals to the
- // pending event that we had shut down. In that case the event bails
- // and does not touch mWindow.
- //
- // 4) happens through DisposeNative directly. OnDetach is not
- // called.
- //
- // 6) is solved by keeping a destroyed flag in the Java NPZC instance,
- // and only make a pending call if the destroyed flag is not set.
- //
- // 7) is solved by taking a lock whenever mWindow is modified on the
- // Gecko thread or accessed on the UI thread. That way, we don't
- // release mWindow until the UI thread is done using it, thus avoiding
- // the race condition.
-
- typedef NativePanZoomController::GlobalRef NPZCRef;
- auto callDestroy = [] (const NPZCRef& npzc) {
- npzc->Destroy();
- };
-
- NativePanZoomController::GlobalRef npzc = mNPZC;
- AndroidBridge::Bridge()->PostTaskToUiThread(NewRunnableFunction(
- static_cast<void(*)(const NPZCRef&)>(callDestroy),
- mozilla::Move(npzc)), 0);
- }
-
-public:
- void AdjustScrollForSurfaceShift(float aX, float aY)
- {
- MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
-
- RefPtr<IAPZCTreeManager> controller;
-
- if (LockedWindowPtr window{mWindow}) {
- controller = window->mAPZC;
- }
-
- if (controller) {
- controller->AdjustScrollForSurfaceShift(
- ScreenPoint(aX, aY));
- }
- }
-
- void SetIsLongpressEnabled(bool aIsLongpressEnabled)
- {
- MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
-
- RefPtr<IAPZCTreeManager> controller;
-
- if (LockedWindowPtr window{mWindow}) {
- controller = window->mAPZC;
- }
-
- if (controller) {
- controller->SetLongTapEnabled(aIsLongpressEnabled);
- }
- }
-
- bool HandleScrollEvent(int64_t aTime, int32_t aMetaState,
- float aX, float aY,
- float aHScroll, float aVScroll)
- {
- MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
-
- RefPtr<IAPZCTreeManager> controller;
-
- if (LockedWindowPtr window{mWindow}) {
- controller = window->mAPZC;
- }
-
- if (!controller) {
- return false;
- }
-
- ScreenPoint origin = ScreenPoint(aX, aY);
-
- ScrollWheelInput input(aTime, TimeStamp::Now(), GetModifiers(aMetaState),
- 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;
- }
-
- NativePanZoomController::GlobalRef npzc = mNPZC;
- nsAppShell::PostEvent([npzc, input, guid, blockId, status] {
- MOZ_ASSERT(NS_IsMainThread());
-
- JNIEnv* const env = jni::GetGeckoThreadEnv();
- NPZCSupport* npzcSupport = GetNative(
- NativePanZoomController::LocalRef(env, npzc));
-
- if (!npzcSupport || !npzcSupport->mWindow) {
- // We already shut down.
- env->ExceptionClear();
- return;
- }
-
- nsWindow* const window = npzcSupport->mWindow;
- window->UserActivity();
- WidgetWheelEvent wheelEvent = input.ToWidgetWheelEvent(window);
- window->ProcessUntransformedAPZEvent(&wheelEvent, guid,
- blockId, status);
- });
-
- return true;
- }
-
-private:
- static MouseInput::ButtonType GetButtonType(int button)
- {
- MouseInput::ButtonType result = MouseInput::NONE;
-
- switch (button) {
- case java::sdk::MotionEvent::BUTTON_PRIMARY:
- result = MouseInput::LEFT_BUTTON;
- break;
- case java::sdk::MotionEvent::BUTTON_SECONDARY:
- result = MouseInput::RIGHT_BUTTON;
- break;
- case java::sdk::MotionEvent::BUTTON_TERTIARY:
- result = MouseInput::MIDDLE_BUTTON;
- break;
- default:
- break;
- }
-
- return result;
- }
-
- static int16_t ConvertButtons(int buttons) {
- int16_t result = 0;
-
- if (buttons & java::sdk::MotionEvent::BUTTON_PRIMARY) {
- result |= WidgetMouseEventBase::eLeftButtonFlag;
- }
- if (buttons & java::sdk::MotionEvent::BUTTON_SECONDARY) {
- result |= WidgetMouseEventBase::eRightButtonFlag;
- }
- if (buttons & java::sdk::MotionEvent::BUTTON_TERTIARY) {
- result |= WidgetMouseEventBase::eMiddleButtonFlag;
- }
- if (buttons & java::sdk::MotionEvent::BUTTON_BACK) {
- result |= WidgetMouseEventBase::e4thButtonFlag;
- }
- if (buttons & java::sdk::MotionEvent::BUTTON_FORWARD) {
- result |= WidgetMouseEventBase::e5thButtonFlag;
- }
-
- return result;
- }
-
-public:
- bool HandleMouseEvent(int32_t aAction, int64_t aTime, int32_t aMetaState,
- float aX, float aY, int buttons)
- {
- MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
-
- RefPtr<IAPZCTreeManager> controller;
-
- if (LockedWindowPtr window{mWindow}) {
- controller = window->mAPZC;
- }
-
- if (!controller) {
- return false;
- }
-
- MouseInput::MouseType mouseType = MouseInput::MOUSE_NONE;
- MouseInput::ButtonType buttonType = MouseInput::NONE;
- switch (aAction) {
- 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;
- case AndroidMotionEvent::ACTION_HOVER_MOVE:
- mouseType = MouseInput::MOUSE_MOVE;
- break;
- case AndroidMotionEvent::ACTION_HOVER_ENTER:
- mouseType = MouseInput::MOUSE_WIDGET_ENTER;
- break;
- case AndroidMotionEvent::ACTION_HOVER_EXIT:
- mouseType = MouseInput::MOUSE_WIDGET_EXIT;
- break;
- default:
- break;
- }
-
- if (mouseType == MouseInput::MOUSE_NONE) {
- return false;
- }
-
- ScreenPoint origin = ScreenPoint(aX, aY);
-
- MouseInput input(mouseType, buttonType, nsIDOMMouseEvent::MOZ_SOURCE_MOUSE, ConvertButtons(buttons), origin, aTime, TimeStamp(), GetModifiers(aMetaState));
-
- ScrollableLayerGuid guid;
- uint64_t blockId;
- nsEventStatus status = controller->ReceiveInputEvent(input, &guid, &blockId);
-
- if (status == nsEventStatus_eConsumeNoDefault) {
- return true;
- }
-
- NativePanZoomController::GlobalRef npzc = mNPZC;
- nsAppShell::PostEvent([npzc, input, guid, blockId, status] {
- MOZ_ASSERT(NS_IsMainThread());
-
- JNIEnv* const env = jni::GetGeckoThreadEnv();
- NPZCSupport* npzcSupport = GetNative(
- NativePanZoomController::LocalRef(env, npzc));
-
- if (!npzcSupport || !npzcSupport->mWindow) {
- // We already shut down.
- env->ExceptionClear();
- return;
- }
-
- nsWindow* const window = npzcSupport->mWindow;
- window->UserActivity();
- WidgetMouseEvent mouseEvent = input.ToWidgetMouseEvent(window);
- window->ProcessUntransformedAPZEvent(&mouseEvent, guid,
- blockId, status);
- });
-
- return true;
- }
-
- 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());
-
- RefPtr<IAPZCTreeManager> controller;
-
- if (LockedWindowPtr window{mWindow}) {
- controller = window->mAPZC;
- }
-
- if (!controller) {
- return false;
- }
-
- nsTArray<int32_t> pointerId(aPointerId->GetElements());
- MultiTouchInput::MultiTouchType type;
- size_t startIndex = 0;
- size_t endIndex = pointerId.Length();
-
- switch (aAction) {
- case sdk::MotionEvent::ACTION_DOWN:
- case sdk::MotionEvent::ACTION_POINTER_DOWN:
- type = MultiTouchInput::MULTITOUCH_START;
- break;
- case sdk::MotionEvent::ACTION_MOVE:
- type = MultiTouchInput::MULTITOUCH_MOVE;
- break;
- case sdk::MotionEvent::ACTION_UP:
- case sdk::MotionEvent::ACTION_POINTER_UP:
- // for pointer-up events we only want the data from
- // the one pointer that went up
- type = MultiTouchInput::MULTITOUCH_END;
- startIndex = aActionIndex;
- endIndex = aActionIndex + 1;
- break;
- case sdk::MotionEvent::ACTION_OUTSIDE:
- case sdk::MotionEvent::ACTION_CANCEL:
- type = MultiTouchInput::MULTITOUCH_CANCEL;
- break;
- default:
- return false;
- }
-
- MultiTouchInput input(type, aTime, TimeStamp(), 0);
- input.modifiers = GetModifiers(aMetaState);
- input.mTouches.SetCapacity(endIndex - startIndex);
-
- nsTArray<float> x(aX->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());
-
- 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])),
- int32_t(floorf(y[i])));
-
- // w3c touchevent radii are given with an orientation between 0 and
- // 90. The radii are found by removing the orientation and
- // measuring the x and y radii of the resulting ellipse. For
- // Android orientations >= 0 and < 90, use the y radius as the
- // major radius, and x as the minor radius. However, for an
- // orientation < 0, we have to shift the orientation by adding 90,
- // and reverse which radius is major and minor.
- gfx::Size radius;
- if (orien < 0.0f) {
- orien += 90.0f;
- radius = gfx::Size(int32_t(toolMajor[i] / 2.0f),
- int32_t(toolMinor[i] / 2.0f));
- } else {
- radius = gfx::Size(int32_t(toolMinor[i] / 2.0f),
- int32_t(toolMajor[i] / 2.0f));
- }
-
- input.mTouches.AppendElement(SingleTouchData(
- pointerId[i], ScreenIntPoint::FromUnknownPoint(point),
- ScreenSize::FromUnknownSize(radius), orien, pressure[i]));
- }
-
- ScrollableLayerGuid guid;
- uint64_t blockId;
- nsEventStatus status =
- controller->ReceiveInputEvent(input, &guid, &blockId);
-
- if (status == nsEventStatus_eConsumeNoDefault) {
- return true;
- }
-
- // Dispatch APZ input event on Gecko thread.
- NativePanZoomController::GlobalRef npzc = mNPZC;
- nsAppShell::PostEvent([npzc, input, guid, blockId, status] {
- MOZ_ASSERT(NS_IsMainThread());
-
- JNIEnv* const env = jni::GetGeckoThreadEnv();
- NPZCSupport* npzcSupport = GetNative(
- NativePanZoomController::LocalRef(env, npzc));
-
- if (!npzcSupport || !npzcSupport->mWindow) {
- // We already shut down.
- env->ExceptionClear();
- return;
- }
-
- nsWindow* const window = npzcSupport->mWindow;
- window->UserActivity();
- WidgetTouchEvent touchEvent = input.ToWidgetTouchEvent(window);
- window->ProcessUntransformedAPZEvent(&touchEvent, guid,
- blockId, status);
- window->DispatchHitTest(touchEvent);
- });
- return true;
- }
-
- void HandleMotionEventVelocity(int64_t aTime, float aSpeedY)
- {
- MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
-
- RefPtr<IAPZCTreeManager> controller;
-
- if (LockedWindowPtr window{mWindow}) {
- controller = window->mAPZC;
- }
-
- if (controller) {
- controller->ProcessTouchVelocity((uint32_t)aTime, aSpeedY);
- }
- }
-
- void UpdateOverscrollVelocity(const float x, const float y)
- {
- mNPZC->UpdateOverscrollVelocity(x, y);
- }
-
- void UpdateOverscrollOffset(const float x, const float y)
- {
- mNPZC->UpdateOverscrollOffset(x, y);
- }
-
- void SetScrollingRootContent(const bool isRootContent)
- {
- mNPZC->SetScrollingRootContent(isRootContent);
- }
-
- void SetSelectionDragState(const bool aState)
- {
- mNPZC->OnSelectionDragState(aState);
- }
-};
-
-template<> const char
-nsWindow::NativePtr<nsWindow::NPZCSupport>::sName[] = "NPZCSupport";
-
-/**
- * Compositor has some unique requirements for its native calls, so make it
- * separate from GeckoViewSupport.
- */
-class nsWindow::LayerViewSupport final
- : public LayerView::Compositor::Natives<LayerViewSupport>
-{
- using LockedWindowPtr = WindowPtr<LayerViewSupport>::Locked;
-
- WindowPtr<LayerViewSupport> mWindow;
- LayerView::Compositor::GlobalRef mCompositor;
- GeckoLayerClient::GlobalRef mLayerClient;
- Atomic<bool, ReleaseAcquire> mCompositorPaused;
- jni::Object::GlobalRef mSurface;
-
- // In order to use Event::HasSameTypeAs in PostTo(), we cannot make
- // LayerViewEvent a template because each template instantiation is
- // a different type. So implement LayerViewEvent as a ProxyEvent.
- class LayerViewEvent final : public nsAppShell::ProxyEvent
- {
- using Event = nsAppShell::Event;
-
- public:
- static UniquePtr<Event> MakeEvent(UniquePtr<Event>&& event)
- {
- return MakeUnique<LayerViewEvent>(mozilla::Move(event));
- }
-
- LayerViewEvent(UniquePtr<Event>&& event)
- : nsAppShell::ProxyEvent(mozilla::Move(event))
- {}
-
- 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);
- }
- }
- };
-
-public:
- typedef LayerView::Compositor::Natives<LayerViewSupport> Base;
-
- template<class Functor>
- static void OnNativeCall(Functor&& aCall)
- {
- if (aCall.IsTarget(&LayerViewSupport::CreateCompositor)) {
- // This call is blocking.
- nsAppShell::SyncRunEvent(nsAppShell::LambdaEvent<Functor>(
- mozilla::Move(aCall)), &LayerViewEvent::MakeEvent);
- return;
- }
- }
-
- static LayerViewSupport*
- FromNative(const LayerView::Compositor::LocalRef& instance)
- {
- return GetNative(instance);
- }
-
- LayerViewSupport(NativePtr<LayerViewSupport>* aPtr, nsWindow* aWindow,
- const LayerView::Compositor::LocalRef& aInstance)
- : mWindow(aPtr, aWindow)
- , mCompositor(aInstance)
- , mCompositorPaused(true)
- {}
-
- ~LayerViewSupport()
- {}
-
- using Base::AttachNative;
- using Base::DisposeNative;
-
- void OnDetach()
- {
- mCompositor->Destroy();
- }
-
- const GeckoLayerClient::Ref& GetLayerClient() const
- {
- return mLayerClient;
- }
-
- bool CompositorPaused() const
- {
- return mCompositorPaused;
- }
-
- jni::Object::Param GetSurface()
- {
- return mSurface;
- }
-
-private:
- void OnResumedCompositor()
- {
- MOZ_ASSERT(NS_IsMainThread());
-
- // 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) {
- mWindow->RedrawAll();
- }
- }
-
- /**
- * Compositor methods
- */
-public:
- void AttachToJava(jni::Object::Param aClient, jni::Object::Param aNPZC)
- {
- MOZ_ASSERT(NS_IsMainThread());
- if (!mWindow) {
- return; // Already shut down.
- }
-
- const auto& layerClient = GeckoLayerClient::Ref::From(aClient);
-
- // If resetting is true, Android destroyed our GeckoApp activity and we
- // had to recreate it, but all the Gecko-side things were not
- // destroyed. We therefore need to link up the new java objects to
- // Gecko, and that's what we do here.
- const bool resetting = !!mLayerClient;
- mLayerClient = layerClient;
-
- MOZ_ASSERT(aNPZC);
- auto npzc = NativePanZoomController::LocalRef(
- jni::GetGeckoThreadEnv(),
- NativePanZoomController::Ref::From(aNPZC));
- mWindow->mNPZCSupport.Attach(npzc, mWindow, npzc);
-
- layerClient->OnGeckoReady();
-
- if (resetting) {
- // Since we are re-linking the new java objects to Gecko, we need
- // to get the viewport from the compositor (since the Java copy was
- // thrown away) and we do that by setting the first-paint flag.
- if (RefPtr<CompositorBridgeParent> bridge = mWindow->GetCompositorBridgeParent()) {
- bridge->ForceIsFirstPaint();
- }
- }
- }
-
- void OnSizeChanged(int32_t aWindowWidth, int32_t aWindowHeight,
- int32_t aScreenWidth, int32_t aScreenHeight)
- {
- MOZ_ASSERT(NS_IsMainThread());
- if (!mWindow) {
- return; // Already shut down.
- }
-
- if (aWindowWidth != mWindow->mBounds.width ||
- aWindowHeight != mWindow->mBounds.height) {
-
- mWindow->Resize(aWindowWidth, aWindowHeight, /* repaint */ false);
- }
- }
-
- void CreateCompositor(int32_t aWidth, int32_t aHeight,
- jni::Object::Param aSurface)
- {
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mWindow);
-
- mSurface = aSurface;
- mWindow->CreateLayerManager(aWidth, aHeight);
-
- mCompositorPaused = false;
- OnResumedCompositor();
- }
-
- void SyncPauseCompositor()
- {
- MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
-
- RefPtr<CompositorBridgeParent> bridge;
-
- if (LockedWindowPtr window{mWindow}) {
- bridge = window->GetCompositorBridgeParent();
- }
-
- if (bridge) {
- mCompositorPaused = true;
- bridge->SchedulePauseOnCompositorThread();
- }
- }
-
- void SyncResumeCompositor()
- {
- MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
-
- RefPtr<CompositorBridgeParent> bridge;
-
- if (LockedWindowPtr window{mWindow}) {
- bridge = window->GetCompositorBridgeParent();
- }
-
- if (bridge && bridge->ScheduleResumeOnCompositorThread()) {
- mCompositorPaused = false;
- }
- }
-
- void SyncResumeResizeCompositor(const LayerView::Compositor::LocalRef& aObj,
- int32_t aWidth, int32_t aHeight,
- jni::Object::Param aSurface)
- {
- MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
-
- RefPtr<CompositorBridgeParent> bridge;
-
- if (LockedWindowPtr window{mWindow}) {
- bridge = window->GetCompositorBridgeParent();
- }
-
- mSurface = aSurface;
-
- if (!bridge || !bridge->ScheduleResumeOnCompositorThread(aWidth,
- aHeight)) {
- return;
- }
-
- 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)));
- }
-
- void SyncInvalidateAndScheduleComposite()
- {
- RefPtr<CompositorBridgeParent> bridge;
-
- if (LockedWindowPtr window{mWindow}) {
- bridge = window->GetCompositorBridgeParent();
- }
-
- if (bridge) {
- bridge->InvalidateOnCompositorThread();
- bridge->ScheduleRenderOnCompositorThread();
- }
- }
-};
-
-template<> const char
-nsWindow::NativePtr<nsWindow::LayerViewSupport>::sName[] = "LayerViewSupport";
-
-/* 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;
-
-
-nsWindow::GeckoViewSupport::~GeckoViewSupport()
-{
- // Disassociate our GeckoEditable instance with our native object.
- // OnDestroy will call disposeNative after any pending native calls have
- // been made.
- MOZ_ASSERT(mEditable);
- mEditable->OnViewChange(nullptr);
-
- if (window.mNPZCSupport) {
- window.mNPZCSupport.Detach();
- }
-
- if (window.mLayerViewSupport) {
- window.mLayerViewSupport.Detach();
- }
-}
-
-/* static */ void
-nsWindow::GeckoViewSupport::Open(const jni::Class::LocalRef& aCls,
- GeckoView::Window::Param aWindow,
- GeckoView::Param aView,
- jni::Object::Param aCompositor,
- jni::String::Param aChromeURI,
- int32_t aScreenId)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- PROFILER_LABEL("nsWindow", "GeckoViewSupport::Open",
- js::ProfileEntry::Category::OTHER);
-
- nsCOMPtr<nsIWindowWatcher> ww = do_GetService(NS_WINDOWWATCHER_CONTRACTID);
- MOZ_RELEASE_ASSERT(ww);
-
- nsAdoptingCString url;
- if (aChromeURI) {
- url = aChromeURI->ToCString();
- } else {
- url = Preferences::GetCString("toolkit.defaultChromeURI");
- if (!url) {
- url = NS_LITERAL_CSTRING("chrome://browser/content/browser.xul");
- }
- }
-
- nsCOMPtr<mozIDOMWindowProxy> domWindow;
- ww->OpenWindow(nullptr, url, nullptr, "chrome,dialog=0,resizable,scrollbars=yes",
- nullptr, getter_AddRefs(domWindow));
- MOZ_RELEASE_ASSERT(domWindow);
-
- nsCOMPtr<nsPIDOMWindowOuter> pdomWindow =
- nsPIDOMWindowOuter::From(domWindow);
- nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(pdomWindow);
- MOZ_ASSERT(widget);
-
- const auto window = static_cast<nsWindow*>(widget.get());
- window->SetScreenId(aScreenId);
-
- // Attach a new GeckoView support object to the new window.
- window->mGeckoViewSupport = mozilla::MakeUnique<GeckoViewSupport>(
- window, GeckoView::Window::LocalRef(aCls.Env(), aWindow), aView);
-
- window->mGeckoViewSupport->mDOMWindow = pdomWindow;
-
- // Attach the Compositor to the new window.
- auto compositor = LayerView::Compositor::LocalRef(
- aCls.Env(), LayerView::Compositor::Ref::From(aCompositor));
- window->mLayerViewSupport.Attach(compositor, window, compositor);
-
- if (window->mWidgetListener) {
- nsCOMPtr<nsIXULWindow> xulWindow(
- window->mWidgetListener->GetXULWindow());
- if (xulWindow) {
- // Our window is not intrinsically sized, so tell nsXULWindow to
- // not set a size for us.
- xulWindow->SetIntrinsicallySized(false);
- }
- }
-}
-
-void
-nsWindow::GeckoViewSupport::Close()
-{
- if (!mDOMWindow) {
- return;
- }
-
- mDOMWindow->ForceClose();
- mDOMWindow = nullptr;
-}
-
-void
-nsWindow::GeckoViewSupport::Reattach(const GeckoView::Window::LocalRef& inst,
- GeckoView::Param aView,
- jni::Object::Param aCompositor)
-{
- // Associate our previous GeckoEditable with the new GeckoView.
- mEditable->OnViewChange(aView);
-
- // 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);
- compositor->Reattach();
-}
-
-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");
- }
-}
-
-void
-nsWindow::InitNatives()
-{
- nsWindow::GeckoViewSupport::Base::Init();
- nsWindow::GeckoViewSupport::EditableBase::Init();
- nsWindow::LayerViewSupport::Init();
- nsWindow::NPZCSupport::Init();
- if (jni::IsFennec()) {
- nsWindow::PMPMSupport::Init();
- }
-}
-
-nsWindow*
-nsWindow::TopWindow()
-{
- if (!gTopLevelWindows.IsEmpty())
- return gTopLevelWindows[0];
- return nullptr;
-}
-
-void
-nsWindow::LogWindow(nsWindow *win, int index, int indent)
-{
-#if defined(DEBUG) || defined(FORCE_ALOG)
- char spaces[] = " ";
- spaces[indent < 20 ? indent : 20] = 0;
- ALOG("%s [% 2d] 0x%08x [parent 0x%08x] [% 3d,% 3dx% 3d,% 3d] vis %d type %d",
- 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);
-#endif
-}
-
-void
-nsWindow::DumpWindows()
-{
- DumpWindows(gTopLevelWindows);
-}
-
-void
-nsWindow::DumpWindows(const nsTArray<nsWindow*>& wins, int indent)
-{
- for (uint32_t i = 0; i < wins.Length(); ++i) {
- nsWindow *w = wins[i];
- LogWindow(w, i, indent);
- DumpWindows(w->mChildren, indent+1);
- }
-}
-
-nsWindow::nsWindow() :
- mScreenId(0), // Use 0 (primary screen) as the default value.
- mIsVisible(false),
- mParent(nullptr),
- mAwaitingFullScreen(false),
- mIsFullScreen(false)
-{
-}
-
-nsWindow::~nsWindow()
-{
- gTopLevelWindows.RemoveElement(this);
- ALOG("nsWindow %p destructor", (void*)this);
-}
-
-bool
-nsWindow::IsTopLevel()
-{
- return mWindowType == eWindowType_toplevel ||
- mWindowType == eWindowType_dialog ||
- mWindowType == eWindowType_invisible;
-}
-
-nsresult
-nsWindow::Create(nsIWidget* aParent,
- nsNativeWidget aNativeParent,
- const LayoutDeviceIntRect& aRect,
- nsWidgetInitData* aInitData)
-{
- ALOG("nsWindow[%p]::Create %p [%d %d %d %d]", (void*)this, (void*)aParent,
- aRect.x, aRect.y, aRect.width, aRect.height);
-
- nsWindow *parent = (nsWindow*) aParent;
- if (aNativeParent) {
- if (parent) {
- ALOG("Ignoring native parent on Android window [%p], "
- "since parent was specified (%p %p)", (void*)this,
- (void*)aNativeParent, (void*)aParent);
- } else {
- parent = (nsWindow*) aNativeParent;
- }
- }
-
- mBounds = aRect;
-
- BaseCreate(nullptr, aInitData);
-
- NS_ASSERTION(IsTopLevel() || parent,
- "non-top-level window doesn't have a parent!");
-
- if (IsTopLevel()) {
- gTopLevelWindows.AppendElement(this);
-
- } else if (parent) {
- parent->mChildren.AppendElement(this);
- mParent = parent;
- }
-
-#ifdef DEBUG_ANDROID_WIDGET
- DumpWindows();
-#endif
-
- return NS_OK;
-}
-
-void
-nsWindow::Destroy()
-{
- nsBaseWidget::mOnDestroyCalled = true;
-
- if (mGeckoViewSupport) {
- // Disassociate our native object with GeckoView.
- mGeckoViewSupport = nullptr;
- }
-
- // Stuff below may release the last ref to this
- nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
-
- while (mChildren.Length()) {
- // why do we still have children?
- ALOG("### Warning: Destroying window %p and reparenting child %p to null!", (void*)this, (void*)mChildren[0]);
- mChildren[0]->SetParent(nullptr);
- }
-
- nsBaseWidget::Destroy();
-
- if (IsTopLevel())
- gTopLevelWindows.RemoveElement(this);
-
- SetParent(nullptr);
-
- nsBaseWidget::OnDestroy();
-
-#ifdef DEBUG_ANDROID_WIDGET
- DumpWindows();
-#endif
-}
-
-NS_IMETHODIMP
-nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>& config)
-{
- for (uint32_t i = 0; i < config.Length(); ++i) {
- nsWindow *childWin = (nsWindow*) config[i].mChild.get();
- childWin->Resize(config[i].mBounds.x,
- config[i].mBounds.y,
- config[i].mBounds.width,
- config[i].mBounds.height,
- false);
- }
-
- return NS_OK;
-}
-
-void
-nsWindow::RedrawAll()
-{
- if (mAttachedWidgetListener) {
- mAttachedWidgetListener->RequestRepaint();
- } else if (mWidgetListener) {
- mWidgetListener->RequestRepaint();
- }
-}
-
-NS_IMETHODIMP
-nsWindow::SetParent(nsIWidget *aNewParent)
-{
- if ((nsIWidget*)mParent == aNewParent)
- return NS_OK;
-
- // If we had a parent before, remove ourselves from its list of
- // children.
- 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
- if (FindTopLevel() == nsWindow::TopWindow())
- RedrawAll();
-
- return NS_OK;
-}
-
-nsIWidget*
-nsWindow::GetParent()
-{
- return mParent;
-}
-
-float
-nsWindow::GetDPI()
-{
- if (AndroidBridge::Bridge())
- return AndroidBridge::Bridge()->GetDPI();
- return 160.0f;
-}
-
-double
-nsWindow::GetDefaultScaleInternal()
-{
-
- nsCOMPtr<nsIScreen> screen = GetWidgetScreen();
- MOZ_ASSERT(screen);
- RefPtr<nsScreenAndroid> screenAndroid = (nsScreenAndroid*) screen.get();
- return screenAndroid->GetDensity();
-}
-
-NS_IMETHODIMP
-nsWindow::Show(bool aState)
-{
- ALOG("nsWindow[%p]::Show %d", (void*)this, aState);
-
- if (mWindowType == eWindowType_invisible) {
- ALOG("trying to show invisible window! ignoring..");
- return NS_ERROR_FAILURE;
- }
-
- if (aState == mIsVisible)
- return NS_OK;
-
- mIsVisible = aState;
-
- if (IsTopLevel()) {
- // XXX should we bring this to the front when it's shown,
- // if it's a toplevel widget?
-
- // XXX we should synthesize a eMouseExitFromWidget (for old top
- // window)/eMouseEnterIntoWidget (for new top window) since we need
- // to pretend that the top window always has focus. Not sure
- // if Show() is the right place to do this, though.
-
- if (aState) {
- // It just became visible, so bring it to the front.
- BringToFront();
-
- } else if (nsWindow::TopWindow() == this) {
- // find the next visible window to show
- unsigned int i;
- for (i = 1; i < gTopLevelWindows.Length(); i++) {
- nsWindow *win = gTopLevelWindows[i];
- if (!win->mIsVisible)
- continue;
-
- win->BringToFront();
- break;
- }
- }
- } else if (FindTopLevel() == nsWindow::TopWindow()) {
- RedrawAll();
- }
-
-#ifdef DEBUG_ANDROID_WIDGET
- DumpWindows();
-#endif
-
- return NS_OK;
-}
-
-bool
-nsWindow::IsVisible() const
-{
- return mIsVisible;
-}
-
-void
-nsWindow::ConstrainPosition(bool aAllowSlop,
- int32_t *aX,
- int32_t *aY)
-{
- 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;
- }
-}
-
-NS_IMETHODIMP
-nsWindow::Move(double aX,
- double aY)
-{
- if (IsTopLevel())
- return NS_OK;
-
- return Resize(aX,
- aY,
- mBounds.width,
- mBounds.height,
- true);
-}
-
-NS_IMETHODIMP
-nsWindow::Resize(double aWidth,
- double aHeight,
- bool aRepaint)
-{
- return Resize(mBounds.x,
- mBounds.y,
- aWidth,
- aHeight,
- aRepaint);
-}
-
-NS_IMETHODIMP
-nsWindow::Resize(double aX,
- double aY,
- double aWidth,
- double aHeight,
- bool aRepaint)
-{
- ALOG("nsWindow[%p]::Resize [%f %f %f %f] (repaint %d)", (void*)this, aX, aY, aWidth, aHeight, aRepaint);
-
- bool needSizeDispatch = aWidth != mBounds.width || aHeight != mBounds.height;
-
- mBounds.x = NSToIntRound(aX);
- mBounds.y = NSToIntRound(aY);
- mBounds.width = NSToIntRound(aWidth);
- mBounds.height = NSToIntRound(aHeight);
-
- if (needSizeDispatch) {
- OnSizeChanged(gfx::IntSize::Truncate(aWidth, aHeight));
- }
-
- // Should we skip honoring aRepaint here?
- if (aRepaint && FindTopLevel() == nsWindow::TopWindow())
- RedrawAll();
-
- nsIWidgetListener* listener = GetWidgetListener();
- if (mAwaitingFullScreen && listener) {
- listener->FullscreenChanged(mIsFullScreen);
- mAwaitingFullScreen = false;
- }
-
- return NS_OK;
-}
-
-void
-nsWindow::SetZIndex(int32_t aZIndex)
-{
- ALOG("nsWindow[%p]::SetZIndex %d ignored", (void*)this, aZIndex);
-}
-
-void
-nsWindow::SetSizeMode(nsSizeMode aMode)
-{
- switch (aMode) {
- case nsSizeMode_Minimized:
- GeckoAppShell::MoveTaskToBack();
- break;
- case nsSizeMode_Fullscreen:
- MakeFullScreen(true);
- break;
- default:
- break;
- }
-}
-
-NS_IMETHODIMP
-nsWindow::Enable(bool aState)
-{
- ALOG("nsWindow[%p]::Enable %d ignored", (void*)this, aState);
- return NS_OK;
-}
-
-bool
-nsWindow::IsEnabled() const
-{
- return true;
-}
-
-NS_IMETHODIMP
-nsWindow::Invalidate(const LayoutDeviceIntRect& aRect)
-{
- return NS_OK;
-}
-
-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;
-}
-
-NS_IMETHODIMP
-nsWindow::SetFocus(bool aRaise)
-{
- nsWindow *top = FindTopLevel();
- top->BringToFront();
-
- return NS_OK;
-}
-
-void
-nsWindow::BringToFront()
-{
- // 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);
- nsCOMPtr<mozIDOMWindowProxy> existingTopWindow;
- fm->GetActiveWindow(getter_AddRefs(existingTopWindow));
- if (existingTopWindow && FindTopLevel() == nsWindow::TopWindow())
- return;
-
- if (!IsTopLevel()) {
- FindTopLevel()->BringToFront();
- return;
- }
-
- RefPtr<nsWindow> kungFuDeathGrip(this);
-
- nsWindow *oldTop = nullptr;
- if (!gTopLevelWindows.IsEmpty()) {
- oldTop = gTopLevelWindows[0];
- }
-
- gTopLevelWindows.RemoveElement(this);
- gTopLevelWindows.InsertElementAt(0, this);
-
- if (oldTop) {
- nsIWidgetListener* listener = oldTop->GetWidgetListener();
- if (listener) {
- listener->WindowDeactivated();
- }
- }
-
- if (mWidgetListener) {
- mWidgetListener->WindowActivated();
- }
-
- RedrawAll();
-}
-
-LayoutDeviceIntRect
-nsWindow::GetScreenBounds()
-{
- return LayoutDeviceIntRect(WidgetToScreenOffset(), mBounds.Size());
-}
-
-LayoutDeviceIntPoint
-nsWindow::WidgetToScreenOffset()
-{
- LayoutDeviceIntPoint p(0, 0);
- nsWindow *w = this;
-
- while (w && !w->IsTopLevel()) {
- p.x += w->mBounds.x;
- p.y += w->mBounds.y;
-
- w = w->mParent;
- }
-
- return p;
-}
-
-NS_IMETHODIMP
-nsWindow::DispatchEvent(WidgetGUIEvent* aEvent,
- nsEventStatus& aStatus)
-{
- aStatus = DispatchEvent(aEvent);
- return NS_OK;
-}
-
-nsEventStatus
-nsWindow::DispatchEvent(WidgetGUIEvent* aEvent)
-{
- if (mAttachedWidgetListener) {
- return mAttachedWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
- } else if (mWidgetListener) {
- return mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
- }
- return nsEventStatus_eIgnore;
-}
-
-nsresult
-nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen*)
-{
- mIsFullScreen = aFullScreen;
- mAwaitingFullScreen = true;
- GeckoAppShell::SetFullScreen(aFullScreen);
- return NS_OK;
-}
-
-mozilla::layers::LayerManager*
-nsWindow::GetLayerManager(PLayerTransactionChild*, LayersBackend, LayerManagerPersistence)
-{
- if (mLayerManager) {
- return mLayerManager;
- }
- return nullptr;
-}
-
-void
-nsWindow::CreateLayerManager(int aCompositorWidth, int aCompositorHeight)
-{
- if (mLayerManager) {
- return;
- }
-
- nsWindow *topLevelWindow = FindTopLevel();
- if (!topLevelWindow || topLevelWindow->mWindowType == eWindowType_invisible) {
- // don't create a layer manager for an invisible top-level window
- return;
- }
-
- // Ensure that gfxPlatform is initialized first.
- gfxPlatform::GetPlatform();
-
- if (ShouldUseOffMainThreadCompositing()) {
- CreateCompositor(aCompositorWidth, aCompositorHeight);
- if (mLayerManager) {
- return;
- }
-
- // If we get here, then off main thread compositing failed to initialize.
- sFailedToCreateGLContext = true;
- }
-
- if (!ComputeShouldAccelerate() || sFailedToCreateGLContext) {
- printf_stderr(" -- creating basic, not accelerated\n");
- mLayerManager = CreateBasicLayerManager();
- }
-}
-
-void
-nsWindow::OnSizeChanged(const gfx::IntSize& aSize)
-{
- ALOG("nsWindow: %p OnSizeChanged [%d %d]", (void*)this, aSize.width, aSize.height);
-
- mBounds.width = aSize.width;
- mBounds.height = aSize.height;
-
- if (mWidgetListener) {
- mWidgetListener->WindowResized(this, aSize.width, aSize.height);
- }
-
- if (mAttachedWidgetListener) {
- mAttachedWidgetListener->WindowResized(this, aSize.width, aSize.height);
- }
-}
-
-void
-nsWindow::InitEvent(WidgetGUIEvent& event, LayoutDeviceIntPoint* aPoint)
-{
- if (aPoint) {
- event.mRefPoint = *aPoint;
- } else {
- event.mRefPoint = LayoutDeviceIntPoint(0, 0);
- }
-
- event.mTime = PR_Now() / 1000;
-}
-
-void
-nsWindow::UpdateOverscrollVelocity(const float aX, const float aY)
-{
- if (NativePtr<NPZCSupport>::Locked npzcs{mNPZCSupport}) {
- npzcs->UpdateOverscrollVelocity(aX, aY);
- }
-}
-
-void
-nsWindow::UpdateOverscrollOffset(const float aX, const float aY)
-{
- if (NativePtr<NPZCSupport>::Locked npzcs{mNPZCSupport}) {
- npzcs->UpdateOverscrollOffset(aX, aY);
- }
-}
-
-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");
-
- if (NativePtr<NPZCSupport>::Locked npzcs{mNPZCSupport}) {
- npzcs->SetScrollingRootContent(isRootContent);
- }
-}
-
-void
-nsWindow::SetSelectionDragState(bool aState)
-{
- if (NativePtr<NPZCSupport>::Locked npzcs{mNPZCSupport}) {
- npzcs->SetSelectionDragState(aState);
- }
-}
-
-void *
-nsWindow::GetNativeData(uint32_t aDataType)
-{
- switch (aDataType) {
- // used by GLContextProviderEGL, nullptr is EGL_DEFAULT_DISPLAY
- case NS_NATIVE_DISPLAY:
- return nullptr;
-
- case NS_NATIVE_WIDGET:
- return (void *) this;
-
- case NS_RAW_NATIVE_IME_CONTEXT: {
- void* pseudoIMEContext = GetPseudoIMEContext();
- if (pseudoIMEContext) {
- return pseudoIMEContext;
- }
- // We assume that there is only one context per process on Android
- return NS_ONLY_ONE_NATIVE_IME_CONTEXT;
- }
-
- case NS_JAVA_SURFACE:
- if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
- return lvs->GetSurface().Get();
- }
- return nullptr;
-
- case NS_PRESENTATION_WINDOW:
- return PMPMSupport::sWindow;
-
- case NS_PRESENTATION_SURFACE:
- return PMPMSupport::sSurface;
- }
-
- return nullptr;
-}
-
-void
-nsWindow::SetNativeData(uint32_t aDataType, uintptr_t aVal)
-{
- switch (aDataType) {
- case NS_PRESENTATION_SURFACE:
- PMPMSupport::sSurface = reinterpret_cast<EGLSurface>(aVal);
- break;
- }
-}
-
-void
-nsWindow::DispatchHitTest(const WidgetTouchEvent& aEvent)
-{
- if (aEvent.mMessage == eTouchStart && aEvent.mTouches.Length() == 1) {
- // 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);
- hittest.mRefPoint = aEvent.mTouches[0]->mRefPoint;
- hittest.mIgnoreRootScrollFrame = true;
- hittest.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
- nsEventStatus status;
- DispatchEvent(&hittest, status);
-
- if (mAPZEventState && hittest.hitCluster) {
- mAPZEventState->ProcessClusterHit();
- }
- }
-}
-
-static unsigned int ConvertAndroidKeyCodeToDOMKeyCode(int androidKeyCode)
-{
- // Special-case alphanumeric keycodes because they are most common.
- if (androidKeyCode >= AKEYCODE_A &&
- androidKeyCode <= AKEYCODE_Z) {
- return androidKeyCode - AKEYCODE_A + NS_VK_A;
- }
-
- if (androidKeyCode >= AKEYCODE_0 &&
- androidKeyCode <= AKEYCODE_9) {
- return androidKeyCode - AKEYCODE_0 + NS_VK_0;
- }
-
- switch (androidKeyCode) {
- // KEYCODE_UNKNOWN (0) ... KEYCODE_HOME (3)
- case AKEYCODE_BACK: return NS_VK_ESCAPE;
- // KEYCODE_CALL (5) ... KEYCODE_POUND (18)
- 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;
- // KEYCODE_VOLUME_POWER (26) ... KEYCODE_Z (54)
- 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;
- // KEYCODE_SYM (63) ... KEYCODE_ENVELOPE (65)
- case AKEYCODE_ENTER: return NS_VK_RETURN;
- case AKEYCODE_DEL: return NS_VK_BACK; // Backspace
- case AKEYCODE_GRAVE: return NS_VK_BACK_QUOTE;
- // KEYCODE_MINUS (69)
- 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;
- // KEYCODE_APOSTROPHE (75)
- case AKEYCODE_SLASH: return NS_VK_SLASH;
- // KEYCODE_AT (77) ... KEYCODE_MEDIA_FAST_FORWARD (90)
- 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;
- // KEYCODE_PICTSYMBOLS (94) ... KEYCODE_BUTTON_MODE (110)
- 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;
- // KEYCODE_META_LEFT (117) ... KEYCODE_FUNCTION (119)
- 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;
- // KEYCODE_FORWARD (125) ... KEYCODE_MEDIA_RECORD (130)
- 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;
- // KEYCODE_NUMPAD_LEFT_PAREN (162) ... KEYCODE_CALCULATOR (210)
-
- // 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;
-
- // the A key is the action key for gamepad devices.
- case AKEYCODE_BUTTON_A: return NS_VK_RETURN;
-
- default:
- ALOG("ConvertAndroidKeyCodeToDOMKeyCode: "
- "No DOM keycode for Android keycode %d", androidKeyCode);
- return 0;
- }
-}
-
-static KeyNameIndex
-ConvertAndroidKeyCodeToKeyNameIndex(int keyCode, int action,
- int domPrintableKeyValue)
-{
- // Special-case alphanumeric keycodes because they are most common.
- if (keyCode >= AKEYCODE_A && keyCode <= AKEYCODE_Z) {
- return KEY_NAME_INDEX_USE_STRING;
- }
-
- if (keyCode >= AKEYCODE_0 && keyCode <= AKEYCODE_9) {
- return KEY_NAME_INDEX_USE_STRING;
- }
-
- switch (keyCode) {
-
-#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
- case AKEYCODE_SPACE:
- 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:
- 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:
- case AKEYCODE_NUMPAD_LEFT_PAREN:
- case AKEYCODE_NUMPAD_RIGHT_PAREN:
-
- case AKEYCODE_YEN: // yen sign key
- case AKEYCODE_RO: // Japanese Ro key
- return KEY_NAME_INDEX_USE_STRING;
-
- case AKEYCODE_ENDCALL:
- case AKEYCODE_NUM: // XXX Not sure
- case AKEYCODE_HEADSETHOOK:
- case AKEYCODE_NOTIFICATION: // 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_MUTE: // mutes the microphone
- case AKEYCODE_MEDIA_CLOSE:
-
- case AKEYCODE_DVR:
-
- 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:
-
- case AKEYCODE_MANNER_MODE:
- case AKEYCODE_3D_MODE:
- case AKEYCODE_CONTACTS:
- return KEY_NAME_INDEX_Unidentified;
-
- case AKEYCODE_UNKNOWN:
- MOZ_ASSERT(
- action != AKEY_EVENT_ACTION_MULTIPLE,
- "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.
- return domPrintableKeyValue ?
- KEY_NAME_INDEX_USE_STRING : KEY_NAME_INDEX_Unidentified;
-
- default:
- ALOG("ConvertAndroidKeyCodeToKeyNameIndex: "
- "No DOM key name index for Android keycode %d", keyCode);
- return KEY_NAME_INDEX_Unidentified;
- }
-}
-
-static CodeNameIndex
-ConvertAndroidScanCodeToCodeNameIndex(int scanCode)
-{
- switch (scanCode) {
-
-#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;
- }
-}
-
-static bool
-IsModifierKey(int32_t keyCode)
-{
- using mozilla::java::sdk::KeyEvent;
- 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;
-}
-
-static Modifiers
-GetModifiers(int32_t metaState)
-{
- using mozilla::java::sdk::KeyEvent;
- 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);
-}
-
-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;
-
- event.mModifiers = GetModifiers(metaState);
-
- if (event.mMessage == eKeyPress) {
- // Android gives us \n, so filter out some control characters.
- event.mIsChar = (charCode >= ' ');
- event.mCharCode = event.mIsChar ? charCode : 0;
- event.mKeyCode = event.mIsChar ? 0 : domKeyCode;
- event.mPluginEvent.Clear();
-
- // 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) {
- event.mModifiers &= ~(MODIFIER_ALT | MODIFIER_CONTROL
- | MODIFIER_META);
- }
-
- } else {
- event.mIsChar = false;
- event.mCharCode = 0;
- event.mKeyCode = domKeyCode;
-
- 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);
- }
-
- event.mIsRepeat =
- (event.mMessage == eKeyDown || event.mMessage == eKeyPress) &&
- ((flags & sdk::KeyEvent::FLAG_LONG_PRESS) || repeatCount);
-
- event.mKeyNameIndex = ConvertAndroidKeyCodeToKeyNameIndex(
- keyCode, action, domPrintableKeyValue);
- event.mCodeNameIndex = ConvertAndroidScanCodeToCodeNameIndex(scanCode);
-
- if (event.mKeyNameIndex == KEY_NAME_INDEX_USE_STRING &&
- domPrintableKeyValue) {
- event.mKeyValue = char16_t(domPrintableKeyValue);
- }
-
- event.mLocation =
- WidgetKeyboardEvent::ComputeLocationFromCodeValue(event.mCodeNameIndex);
- event.mTime = time;
-}
-
-void
-nsWindow::GeckoViewSupport::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,
- bool aIsSynthesizedImeKey, jni::Object::Param originalEvent)
-{
- RefPtr<nsWindow> kungFuDeathGrip(&window);
- if (!aIsSynthesizedImeKey) {
- window.UserActivity();
- window.RemoveIMEComposition();
- }
-
- EventMessage msg;
- if (aAction == sdk::KeyEvent::ACTION_DOWN) {
- msg = eKeyDown;
- } else if (aAction == sdk::KeyEvent::ACTION_UP) {
- msg = eKeyUp;
- } else if (aAction == sdk::KeyEvent::ACTION_MULTIPLE) {
- // Keys with multiple action are handled in Java,
- // and we should never see one here
- MOZ_CRASH("Cannot handle key with multiple action");
- } else {
- ALOG("Unknown key action event!");
- return;
- }
-
- nsEventStatus status = nsEventStatus_eIgnore;
- WidgetKeyboardEvent event(true, msg, &window);
- window.InitEvent(event, nullptr);
- InitKeyEvent(event, aAction, aKeyCode, aScanCode, aMetaState, aTime,
- aUnicodeChar, aBaseUnicodeChar, aDomPrintableKeyValue,
- aRepeatCount, aFlags);
-
- if (aIsSynthesizedImeKey) {
- // 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.
- mIMEKeyEvents.AppendElement(
- mozilla::UniquePtr<WidgetEvent>(event.Duplicate()));
-
- } else {
- window.DispatchEvent(&event, status);
-
- if (window.Destroyed() || status == nsEventStatus_eConsumeNoDefault) {
- // Skip default processing.
- return;
- }
-
- mEditable->OnDefaultKeyEvent(originalEvent);
- }
-
- if (msg != eKeyDown || IsModifierKey(aKeyCode)) {
- // Skip sending key press event.
- return;
- }
-
- WidgetKeyboardEvent pressEvent(true, eKeyPress, &window);
- window.InitEvent(pressEvent, nullptr);
- InitKeyEvent(pressEvent, aAction, aKeyCode, aScanCode, aMetaState, aTime,
- aUnicodeChar, aBaseUnicodeChar, aDomPrintableKeyValue,
- aRepeatCount, aFlags);
-
- if (aIsSynthesizedImeKey) {
- mIMEKeyEvents.AppendElement(
- mozilla::UniquePtr<WidgetEvent>(pressEvent.Duplicate()));
- } else {
- window.DispatchEvent(&pressEvent, status);
- }
-}
-
-#ifdef DEBUG_ANDROID_IME
-#define ALOGIME(args...) ALOG(args)
-#else
-#define ALOGIME(args...) ((void)0)
-#endif
-
-static nscolor
-ConvertAndroidColor(uint32_t aArgb)
-{
- return NS_RGBA((aArgb & 0x00ff0000) >> 16,
- (aArgb & 0x0000ff00) >> 8,
- (aArgb & 0x000000ff),
- (aArgb & 0xff000000) >> 24);
-}
-
-/*
- * Get the current composition object, if any.
- */
-RefPtr<mozilla::TextComposition>
-nsWindow::GetIMEComposition()
-{
- MOZ_ASSERT(this == FindTopLevel());
- return mozilla::IMEStateManager::GetTextCompositionFor(this);
-}
-
-/*
- Remove the composition but leave the text content as-is
-*/
-void
-nsWindow::RemoveIMEComposition(RemoveIMECompositionFlag aFlag)
-{
- // Remove composition on Gecko side
- const RefPtr<mozilla::TextComposition> composition(GetIMEComposition());
- if (!composition) {
- return;
- }
-
- RefPtr<nsWindow> kungFuDeathGrip(this);
-
- WidgetCompositionEvent compositionCommitEvent(
- true, eCompositionCommit, this);
- if (aFlag == COMMIT_IME_COMPOSITION) {
- compositionCommitEvent.mMessage = eCompositionCommitAsIs;
- }
- InitEvent(compositionCommitEvent, nullptr);
- DispatchEvent(&compositionCommitEvent);
-}
-
-/*
- * 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
-nsWindow::GeckoViewSupport::SendIMEDummyKeyEvents()
-{
- WidgetKeyboardEvent downEvent(true, eKeyDown, &window);
- window.InitEvent(downEvent, nullptr);
- MOZ_ASSERT(downEvent.mKeyCode == 0);
- window.DispatchEvent(&downEvent);
-
- WidgetKeyboardEvent upEvent(true, eKeyUp, &window);
- window.InitEvent(upEvent, nullptr);
- MOZ_ASSERT(upEvent.mKeyCode == 0);
- window.DispatchEvent(&upEvent);
-}
-
-void
-nsWindow::GeckoViewSupport::AddIMETextChange(const IMETextChange& aChange)
-{
- mIMETextChanges.AppendElement(aChange);
-
- // We may not be in the middle of flushing,
- // in which case this flag is meaningless.
- mIMETextChangedDuringFlush = true;
-
- // 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;
- }
- }
-
- // 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;
-
- 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;
- }
-}
-
-void
-nsWindow::GeckoViewSupport::PostFlushIMEChanges()
-{
- if (!mIMETextChanges.IsEmpty() || mIMESelectionChanged) {
- // Already posted
- return;
- }
-
- // Keep a strong reference to the window to keep 'this' alive.
- RefPtr<nsWindow> window(&this->window);
-
- nsAppShell::PostEvent([this, window] {
- if (!window->Destroyed()) {
- FlushIMEChanges();
- }
- });
-}
-
-void
-nsWindow::GeckoViewSupport::FlushIMEChanges(FlushChangesFlag aFlags)
-{
- // Only send change notifications if we are *not* masking events,
- // i.e. if we have a focused editor,
- NS_ENSURE_TRUE_VOID(!mIMEMaskEventsCount);
-
- nsCOMPtr<nsISelection> imeSelection;
- nsCOMPtr<nsIContent> imeRoot;
-
- // If we are receiving notifications, we must have selection/root content.
- MOZ_ALWAYS_SUCCEEDS(IMEStateManager::GetFocusSelectionAndRoot(
- getter_AddRefs(imeSelection), getter_AddRefs(imeRoot)));
-
- // Make sure we still have a valid selection/root. We can potentially get
- // a stale selection/root if the editor becomes hidden, for example.
- NS_ENSURE_TRUE_VOID(imeRoot->IsInComposedDoc());
-
- RefPtr<nsWindow> kungFuDeathGrip(&window);
- window.UserActivity();
-
- struct TextRecord {
- nsString text;
- int32_t start;
- int32_t oldEnd;
- int32_t newEnd;
- };
- AutoTArray<TextRecord, 4> textTransaction;
- if (mIMETextChanges.Length() > textTransaction.Capacity()) {
- textTransaction.SetCapacity(mIMETextChanges.Length());
- }
-
- mIMETextChangedDuringFlush = false;
-
- 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.
- if (aFlags == FLUSH_FLAG_NONE) {
- 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;
- };
-
- for (const IMETextChange &change : mIMETextChanges) {
- if (change.mStart == change.mOldEnd &&
- change.mStart == change.mNewEnd) {
- continue;
- }
-
- WidgetQueryContentEvent event(true, eQueryTextContent, &window);
-
- 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);
- NS_ENSURE_TRUE_VOID(event.mReply.mContentsRoot == imeRoot.get());
- }
-
- if (shouldAbort()) {
- return;
- }
-
- textTransaction.AppendElement(
- TextRecord{event.mReply.mString, change.mStart,
- change.mOldEnd, change.mNewEnd});
- }
-
- int32_t selStart = -1;
- int32_t selEnd = -1;
-
- if (mIMESelectionChanged) {
- WidgetQueryContentEvent event(true, eQuerySelectedText, &window);
- window.InitEvent(event, nullptr);
- window.DispatchEvent(&event);
-
- NS_ENSURE_TRUE_VOID(event.mSucceeded);
- NS_ENSURE_TRUE_VOID(event.mReply.mContentsRoot == imeRoot.get());
-
- if (shouldAbort()) {
- return;
- }
-
- selStart = int32_t(event.GetSelectionStart());
- selEnd = int32_t(event.GetSelectionEnd());
- }
-
- 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;
- };
-
- // 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);
- if (flushOnException()) {
- return;
- }
- }
-
- if (mIMESelectionChanged) {
- mIMESelectionChanged = false;
- mEditable->OnSelectionChange(selStart, selEnd);
- flushOnException();
- }
-}
-
-void
-nsWindow::GeckoViewSupport::FlushIMEText(FlushChangesFlag aFlags)
-{
- // 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);
-
- FlushIMEChanges(aFlags);
-}
-
-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);
-}
-
-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);
- });
-}
-
-bool
-nsWindow::GeckoViewSupport::NotifyIME(const IMENotification& aIMENotification)
-{
- MOZ_ASSERT(mEditable);
-
- switch (aIMENotification.mMessage) {
- case REQUEST_TO_COMMIT_COMPOSITION: {
- ALOGIME("IME: REQUEST_TO_COMMIT_COMPOSITION");
-
- window.RemoveIMEComposition();
-
- AsyncNotifyIME(GeckoEditableListener::
- NOTIFY_IME_TO_COMMIT_COMPOSITION);
- return true;
- }
-
- case REQUEST_TO_CANCEL_COMPOSITION: {
- ALOGIME("IME: REQUEST_TO_CANCEL_COMPOSITION");
-
- window.RemoveIMEComposition(CANCEL_IME_COMPOSITION);
-
- AsyncNotifyIME(GeckoEditableListener::
- NOTIFY_IME_TO_CANCEL_COMPOSITION);
- return true;
- }
-
- case NOTIFY_IME_OF_FOCUS: {
- ALOGIME("IME: NOTIFY_IME_OF_FOCUS");
- // 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);
- });
- return true;
- }
-
- case NOTIFY_IME_OF_BLUR: {
- ALOGIME("IME: NOTIFY_IME_OF_BLUR");
-
- if (!mIMEMaskEventsCount) {
- mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_OF_BLUR);
- }
-
- // Mask events because we lost focus. Unmask on the next focus.
- mIMEMaskEventsCount++;
- return true;
- }
-
- case NOTIFY_IME_OF_SELECTION_CHANGE: {
- ALOGIME("IME: NOTIFY_IME_OF_SELECTION_CHANGE");
-
- PostFlushIMEChanges();
- mIMESelectionChanged = true;
- return true;
- }
-
- 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;
- }
-
- 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;
- }
-
- default:
- return false;
- }
-}
-
-void
-nsWindow::GeckoViewSupport::SetInputContext(const InputContext& aContext,
- const InputContextAction& aAction)
-{
- MOZ_ASSERT(mEditable);
-
- ALOGIME("IME: SetInputContext: s=0x%X, 0x%X, action=0x%X, 0x%X",
- aContext.mIMEState.mEnabled, aContext.mIMEState.mOpen,
- aAction.mCause, aAction.mFocusChange);
-
- // Ensure that opening the virtual keyboard is allowed for this specific
- // InputContext depending on the content.ime.strict.policy pref
- if (aContext.mIMEState.mEnabled != IMEState::DISABLED &&
- aContext.mIMEState.mEnabled != IMEState::PLUGIN &&
- Preferences::GetBool("content.ime.strict_policy", false) &&
- !aAction.ContentGotFocusByTrustedCause() &&
- !aAction.UserMightRequestOpenVKB()) {
- return;
- }
-
- IMEState::Enabled enabled = aContext.mIMEState.mEnabled;
-
- // 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) {
- enabled = IMEState::DISABLED;
- }
-
- mInputContext = aContext;
- mInputContext.mIMEState.mEnabled = enabled;
-
- if (enabled == IMEState::ENABLED && aAction.UserMightRequestOpenVKB()) {
- // Don't reset keyboard when we should simply open the vkb
- mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_OPEN_VKB);
- return;
- }
-
- if (mIMEUpdatingContext) {
- return;
- }
-
- // Keep a strong reference to the window to keep 'this' alive.
- RefPtr<nsWindow> window(&this->window);
- mIMEUpdatingContext = true;
-
- nsAppShell::PostEvent([this, window] {
- mIMEUpdatingContext = false;
- if (window->Destroyed()) {
- return;
- }
- MOZ_ASSERT(mEditable);
- mEditable->NotifyIMEContext(mInputContext.mIMEState.mEnabled,
- mInputContext.mHTMLInputType,
- mInputContext.mHTMLInputInputmode,
- mInputContext.mActionHint);
- });
-}
-
-InputContext
-nsWindow::GeckoViewSupport::GetInputContext()
-{
- InputContext context = mInputContext;
- context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
- return context;
-}
-
-void
-nsWindow::GeckoViewSupport::OnImeSynchronize()
-{
- if (!mIMEMaskEventsCount) {
- FlushIMEChanges();
- }
- mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_REPLY_EVENT);
-}
-
-void
-nsWindow::GeckoViewSupport::OnImeReplaceText(int32_t aStart, int32_t aEnd,
- jni::String::Param aText)
-{
- AutoIMESynchronize as(this);
-
- if (mIMEMaskEventsCount > 0) {
- // Not focused; still reply to events, but don't do anything else.
- return;
- }
-
- /*
- Replace text in Gecko thread from aStart to aEnd with the string text.
- */
- RefPtr<nsWindow> kungFuDeathGrip(&window);
- nsString string(aText->ToString());
-
- const auto composition(window.GetIMEComposition());
- MOZ_ASSERT(!composition || !composition->IsEditorHandlingEvent());
-
- const bool composing = !mIMERanges->IsEmpty();
-
- 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();
-
- {
- // Use text selection to set target postion(s) for
- // insert, or replace, of text.
- WidgetSelectionEvent event(true, eSetSelection, &window);
- window.InitEvent(event, nullptr);
- event.mOffset = uint32_t(aStart);
- event.mLength = uint32_t(aEnd - aStart);
- event.mExpandToClusterBoundary = false;
- event.mReason = nsISelectionListener::IME_REASON;
- window.DispatchEvent(&event);
- }
-
- 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.
- event->mWidget = &window;
- window.DispatchEvent(event, status);
- }
- mIMEKeyEvents.Clear();
- return;
- }
-
- 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()) {
- WidgetCompositionEvent event(true, eCompositionStart, &window);
- window.InitEvent(event, nullptr);
- window.DispatchEvent(&event);
- }
-
- } 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);
- }
-
- // Check composition again because previous events may have destroyed our
- // composition; in which case we should just skip the next event.
- if (window.GetIMEComposition()) {
- WidgetCompositionEvent event(true, eCompositionChange, &window);
- window.InitEvent(event, nullptr);
- event.mData = string;
-
- if (composing) {
- event.mRanges = new TextRangeArray();
- mIMERanges.swap(event.mRanges);
- } else {
- event.mMessage = eCompositionCommit;
- }
-
- window.DispatchEvent(&event);
-
- } else if (composing) {
- // Ensure IME ranges are empty.
- mIMERanges->Clear();
- }
-
- if (mInputContext.mMayBeIMEUnaware) {
- SendIMEDummyKeyEvents();
- }
-}
-
-void
-nsWindow::GeckoViewSupport::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)
-{
- if (mIMEMaskEventsCount > 0) {
- // Not focused.
- return;
- }
-
- TextRange range;
- range.mStartOffset = aStart;
- range.mEndOffset = aEnd;
- range.mRangeType = ToTextRangeType(aRangeType);
- 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);
-}
-
-void
-nsWindow::GeckoViewSupport::OnImeUpdateComposition(int32_t aStart, int32_t aEnd)
-{
- if (mIMEMaskEventsCount > 0) {
- // Not focused.
- return;
- }
-
- RefPtr<nsWindow> kungFuDeathGrip(&window);
-
- // 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;
- }
-
- /*
- 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;
- event.mReason = nsISelectionListener::IME_REASON;
- window.DispatchEvent(&event);
- }
-
- {
- WidgetQueryContentEvent queryEvent(true, eQuerySelectedText,
- &window);
- window.InitEvent(queryEvent, nullptr);
- window.DispatchEvent(&queryEvent);
- MOZ_ASSERT(queryEvent.mSucceeded);
- event.mData = queryEvent.mReply.mString;
- }
-
- {
- 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);
- }
-}
-
-void
-nsWindow::GeckoViewSupport::OnImeRequestCursorUpdates(int aRequestMode)
-{
- if (aRequestMode == IME_MONITOR_CURSOR_ONE_SHOT) {
- UpdateCompositionRects();
- return;
- }
-
- mIMEMonitorCursor = (aRequestMode == IME_MONITOR_CURSOR_START_MONITOR);
-}
-
-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());
-
- if (!mGeckoViewSupport) {
- // Non-GeckoView windows don't support IME operations.
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- if (mGeckoViewSupport->NotifyIME(aIMENotification)) {
- return NS_OK;
- }
- return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP_(void)
-nsWindow::SetInputContext(const InputContext& aContext,
- const InputContextAction& aAction)
-{
- nsWindow* top = FindTopLevel();
- MOZ_ASSERT(top);
-
- if (!top->mGeckoViewSupport) {
- // Non-GeckoView windows don't support IME operations.
- return;
- }
-
- // 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
- top->mGeckoViewSupport->SetInputContext(aContext, aAction);
-}
-
-NS_IMETHODIMP_(InputContext)
-nsWindow::GetInputContext()
-{
- nsWindow* top = FindTopLevel();
- MOZ_ASSERT(top);
-
- if (!top->mGeckoViewSupport) {
- // 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.
- return top->mGeckoViewSupport->GetInputContext();
-}
-
-nsIMEUpdatePreference
-nsWindow::GetIMEUpdatePreference()
-{
- // While a plugin has focus, nsWindow for Android doesn't need any
- // notifications.
- if (GetInputContext().mIMEState.mEnabled == IMEState::PLUGIN) {
- return nsIMEUpdatePreference();
- }
- return nsIMEUpdatePreference(nsIMEUpdatePreference::NOTIFY_TEXT_CHANGE);
-}
-
-nsresult
-nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId,
- TouchPointerState aPointerState,
- LayoutDeviceIntPoint aPoint,
- 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;
- }
-
- MOZ_ASSERT(mLayerViewSupport);
- GeckoLayerClient::LocalRef client = mLayerViewSupport->GetLayerClient();
- client->SynthesizeNativeTouchPoint(aPointerId, eventType,
- aPoint.x, aPoint.y, aPointerPressure, aPointerOrientation);
-
- return NS_OK;
-}
-
-nsresult
-nsWindow::SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
- uint32_t aNativeMessage,
- uint32_t aModifierFlags,
- nsIObserver* aObserver)
-{
- mozilla::widget::AutoObserverNotifier notifier(aObserver, "mouseevent");
-
- MOZ_ASSERT(mLayerViewSupport);
- GeckoLayerClient::LocalRef client = mLayerViewSupport->GetLayerClient();
- client->SynthesizeNativeMouseEvent(aNativeMessage, aPoint.x, aPoint.y);
-
- return NS_OK;
-}
-
-nsresult
-nsWindow::SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
- nsIObserver* aObserver)
-{
- mozilla::widget::AutoObserverNotifier notifier(aObserver, "mouseevent");
-
- MOZ_ASSERT(mLayerViewSupport);
- GeckoLayerClient::LocalRef client = mLayerViewSupport->GetLayerClient();
- client->SynthesizeNativeMouseEvent(sdk::MotionEvent::ACTION_HOVER_MOVE, aPoint.x, aPoint.y);
-
- return NS_OK;
-}
-
-bool
-nsWindow::PreRender(WidgetRenderingContext* aContext)
-{
- if (Destroyed()) {
- return true;
- }
-
- layers::Compositor* compositor = aContext->mCompositor;
-
- 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;
-}
-void
-nsWindow::DrawWindowUnderlay(WidgetRenderingContext* aContext,
- LayoutDeviceIntRect aRect)
-{
- if (Destroyed()) {
- return;
- }
-
- GeckoLayerClient::LocalRef client;
-
- if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
- client = lvs->GetLayerClient();
- }
-
- if (!client) {
- return;
- }
-
- LayerRenderer::Frame::LocalRef frame = client->CreateFrame();
- mLayerRendererFrame = frame;
- if (NS_WARN_IF(!mLayerRendererFrame)) {
- return;
- }
-
- if (!WidgetPaintsBackground()) {
- return;
- }
-
- frame->BeginDrawing();
-}
-
-void
-nsWindow::DrawWindowOverlay(WidgetRenderingContext* aContext,
- LayoutDeviceIntRect aRect)
-{
- PROFILER_LABEL("nsWindow", "DrawWindowOverlay",
- js::ProfileEntry::Category::GRAPHICS);
-
- if (Destroyed() || NS_WARN_IF(!mLayerRendererFrame)) {
- return;
- }
-
- mLayerRendererFrame->EndDrawing();
- mLayerRendererFrame = nullptr;
-}
-
-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;
-}
-
-bool
-nsWindow::NeedsPaint()
-{
- if (!mLayerViewSupport || mLayerViewSupport->CompositorPaused() ||
- // FindTopLevel() != nsWindow::TopWindow() ||
- !GetLayerManager(nullptr)) {
- return false;
- }
- return nsIWidget::NeedsPaint();
-}
-
-void
-nsWindow::ConfigureAPZControllerThread()
-{
- APZThreadUtils::SetControllerThread(nullptr);
-}
-
-already_AddRefed<GeckoContentController>
-nsWindow::CreateRootContentController()
-{
- RefPtr<GeckoContentController> controller = new AndroidContentController(this, mAPZEventState, mAPZC);
- return controller.forget();
-}
-
-uint32_t
-nsWindow::GetMaxTouchPoints() const
-{
- return GeckoAppShell::GetMaxTouchPoints();
-}
-
-void
-nsWindow::UpdateZoomConstraints(const uint32_t& aPresShellId,
- const FrameMetrics::ViewID& aViewId,
- const mozilla::Maybe<ZoomConstraints>& aConstraints)
-{
- nsBaseWidget::UpdateZoomConstraints(aPresShellId, aViewId, aConstraints);
-}
-
-CompositorBridgeParent*
-nsWindow::GetCompositorBridgeParent() const
-{
- return mCompositorSession ? mCompositorSession->GetInProcessBridge() : nullptr;
-}
-
-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();
-}
-
-jni::DependentRef<java::GeckoLayerClient>
-nsWindow::GetLayerClient()
-{
- if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
- return lvs->GetLayerClient().Get();
- }
- return nullptr;
-}