1 /* -*- Mode: c++; c-basic-offset: 2; tab-width: 4; indent-tabs-mode: nil; -*-
2  * vim: set sw=2 ts=4 expandtab:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include <android/log.h>
8 #include <android/native_window.h>
9 #include <android/native_window_jni.h>
10 #include <math.h>
11 #include <queue>
12 #include <type_traits>
13 #include <unistd.h>
14 
15 #include "mozilla/MiscEvents.h"
16 #include "mozilla/MouseEvents.h"
17 #include "mozilla/Preferences.h"
18 #include "mozilla/RWLock.h"
19 #include "mozilla/StaticPrefs_android.h"
20 #include "mozilla/StaticPrefs_ui.h"
21 #include "mozilla/TouchEvents.h"
22 #include "mozilla/Unused.h"
23 #include "mozilla/WeakPtr.h"
24 #include "mozilla/WheelHandlingHelper.h"  // for WheelDeltaAdjustmentStrategy
25 
26 #include "mozilla/Preferences.h"
27 #include "mozilla/Unused.h"
28 #include "mozilla/a11y/SessionAccessibility.h"
29 #include "mozilla/dom/ContentChild.h"
30 #include "mozilla/dom/ContentParent.h"
31 #include "mozilla/dom/MouseEventBinding.h"
32 #include "mozilla/gfx/2D.h"
33 #include "mozilla/gfx/DataSurfaceHelpers.h"
34 #include "mozilla/layers/RenderTrace.h"
35 #include <algorithm>
36 
37 using mozilla::Unused;
38 using mozilla::dom::ContentChild;
39 using mozilla::dom::ContentParent;
40 
41 #include "nsWindow.h"
42 
43 #include "AndroidGraphics.h"
44 #include "JavaExceptions.h"
45 
46 #include "nsIWidgetListener.h"
47 #include "nsIWindowWatcher.h"
48 #include "nsIAppWindow.h"
49 
50 #include "nsAppShell.h"
51 #include "nsFocusManager.h"
52 #include "nsIdleService.h"
53 #include "nsLayoutUtils.h"
54 #include "nsViewManager.h"
55 
56 #include "WidgetUtils.h"
57 #include "nsContentUtils.h"
58 
59 #include "nsGfxCIID.h"
60 #include "nsGkAtoms.h"
61 #include "nsWidgetsCID.h"
62 
63 #include "gfxContext.h"
64 
65 #include "AndroidContentController.h"
66 #include "GLContext.h"
67 #include "GLContextProvider.h"
68 #include "Layers.h"
69 #include "ScopedGLHelpers.h"
70 #include "mozilla/layers/APZEventState.h"
71 #include "mozilla/layers/APZInputBridge.h"
72 #include "mozilla/layers/APZThreadUtils.h"
73 #include "mozilla/layers/AsyncCompositionManager.h"
74 #include "mozilla/layers/CompositorOGL.h"
75 #include "mozilla/layers/IAPZCTreeManager.h"
76 #include "mozilla/layers/LayerManagerComposite.h"
77 
78 #include "nsTArray.h"
79 
80 #include "AndroidBridge.h"
81 #include "AndroidBridgeUtilities.h"
82 #include "AndroidUiThread.h"
83 #include "GeckoEditableSupport.h"
84 #include "KeyEvent.h"
85 #include "MotionEvent.h"
86 #include "mozilla/java/EventDispatcherWrappers.h"
87 #include "mozilla/java/GeckoAppShellWrappers.h"
88 #include "mozilla/java/GeckoEditableChildWrappers.h"
89 #include "mozilla/java/GeckoResultWrappers.h"
90 #include "mozilla/java/GeckoSessionNatives.h"
91 #include "mozilla/java/GeckoSystemStateListenerWrappers.h"
92 #include "mozilla/java/PanZoomControllerNatives.h"
93 #include "mozilla/java/SessionAccessibilityWrappers.h"
94 #include "ScreenHelperAndroid.h"
95 
96 #include "GeckoProfiler.h"  // For AUTO_PROFILER_LABEL
97 #include "nsPrintfCString.h"
98 #include "nsString.h"
99 
100 #include "JavaBuiltins.h"
101 
102 #include "mozilla/ipc/Shmem.h"
103 
104 using namespace mozilla;
105 using namespace mozilla::dom;
106 using namespace mozilla::layers;
107 using namespace mozilla::widget;
108 using namespace mozilla::ipc;
109 
110 using mozilla::java::GeckoSession;
111 
112 #include "mozilla/layers/CompositorBridgeChild.h"
113 #include "mozilla/layers/CompositorSession.h"
114 #include "mozilla/layers/LayerTransactionParent.h"
115 #include "mozilla/layers/UiCompositorControllerChild.h"
116 #include "nsThreadUtils.h"
117 
118 // All the toplevel windows that have been created; these are in
119 // stacking order, so the window at gTopLevelWindows[0] is the topmost
120 // one.
121 static nsTArray<nsWindow*> gTopLevelWindows;
122 
123 static bool sFailedToCreateGLContext = false;
124 
125 // Multitouch swipe thresholds in inches
126 static const double SWIPE_MAX_PINCH_DELTA_INCHES = 0.4;
127 static const double SWIPE_MIN_DISTANCE_INCHES = 0.6;
128 
129 static const int32_t INPUT_RESULT_UNHANDLED =
130     java::PanZoomController::INPUT_RESULT_UNHANDLED;
131 static const int32_t INPUT_RESULT_HANDLED =
132     java::PanZoomController::INPUT_RESULT_HANDLED;
133 static const int32_t INPUT_RESULT_HANDLED_CONTENT =
134     java::PanZoomController::INPUT_RESULT_HANDLED_CONTENT;
135 
136 template <typename Lambda, bool IsStatic, typename InstanceType, class Impl>
137 class nsWindow::WindowEvent : public Runnable {
IsStaleCall()138   bool IsStaleCall() {
139     if (IsStatic) {
140       // Static calls are never stale.
141       return false;
142     }
143 
144     JNIEnv* const env = mozilla::jni::GetEnvForThread();
145 
146     const auto natives = reinterpret_cast<mozilla::WeakPtr<Impl>*>(
147         jni::GetNativeHandle(env, mInstance.Get()));
148     MOZ_CATCH_JNI_EXCEPTION(env);
149 
150     // The call is stale if the nsWindow has been destroyed on the
151     // Gecko side, but the Java object is still attached to it through
152     // a weak pointer. Stale calls should be discarded. Note that it's
153     // an error if natives is nullptr here; we return false but the
154     // native call will throw an error.
155     return natives && !natives->get();
156   }
157 
158   Lambda mLambda;
159   const InstanceType mInstance;
160 
161  public:
WindowEvent(Lambda && aLambda,InstanceType && aInstance)162   WindowEvent(Lambda&& aLambda, InstanceType&& aInstance)
163       : Runnable("nsWindowEvent"),
164         mLambda(std::move(aLambda)),
165         mInstance(std::forward<InstanceType>(aInstance)) {}
166 
WindowEvent(Lambda && aLambda)167   explicit WindowEvent(Lambda&& aLambda)
168       : Runnable("nsWindowEvent"),
169         mLambda(std::move(aLambda)),
170         mInstance(mLambda.GetThisArg()) {}
171 
Run()172   NS_IMETHOD Run() override {
173     if (!IsStaleCall()) {
174       mLambda();
175     }
176     return NS_OK;
177   }
178 };
179 
180 namespace {
181 template <class Instance, class Impl>
182 std::enable_if_t<
183     jni::detail::NativePtrPicker<Impl>::value == jni::detail::REFPTR, void>
CallAttachNative(Instance aInstance,Impl * aImpl)184 CallAttachNative(Instance aInstance, Impl* aImpl) {
185   Impl::AttachNative(aInstance, RefPtr<Impl>(aImpl).get());
186 }
187 
188 template <class Instance, class Impl>
189 std::enable_if_t<
190     jni::detail::NativePtrPicker<Impl>::value == jni::detail::OWNING, void>
CallAttachNative(Instance aInstance,Impl * aImpl)191 CallAttachNative(Instance aInstance, Impl* aImpl) {
192   Impl::AttachNative(aInstance, UniquePtr<Impl>(aImpl));
193 }
194 
195 template <class Lambda>
DispatchToUiThread(const char * aName,Lambda && aLambda)196 bool DispatchToUiThread(const char* aName, Lambda&& aLambda) {
197   if (RefPtr<nsThread> uiThread = GetAndroidUiThread()) {
198     uiThread->Dispatch(NS_NewRunnableFunction(aName, std::move(aLambda)));
199     return true;
200   }
201   return false;
202 }
203 }  // namespace
204 
205 template <class Impl>
206 template <class Cls, typename... Args>
Attach(const jni::LocalRef<Cls> & aInstance,nsWindow * aWindow,Args &&...aArgs)207 void nsWindow::NativePtr<Impl>::Attach(const jni::LocalRef<Cls>& aInstance,
208                                        nsWindow* aWindow, Args&&... aArgs) {
209   MOZ_ASSERT(NS_IsMainThread());
210   MOZ_ASSERT(!mPtr && !mImpl);
211 
212   Impl* const impl = new Impl(this, aWindow, std::forward<Args>(aArgs)...);
213   mImpl = impl;
214 
215   // CallAttachNative transfers ownership of impl.
216   CallAttachNative<>(aInstance, impl);
217 }
218 
219 template <class Impl>
220 template <class Cls, typename T>
Detach(const jni::Ref<Cls,T> & aInstance)221 void nsWindow::NativePtr<Impl>::Detach(const jni::Ref<Cls, T>& aInstance) {
222   MOZ_ASSERT(NS_IsMainThread());
223   MOZ_ASSERT(mPtr && mImpl);
224 
225   // nsIRunnable that takes care of disposing the native object attached to
226   // the Java object in a safe manner.
227   class ImplDisposer : public Runnable {
228     const typename Cls::GlobalRef mInstance;
229     const uintptr_t mOldImpl;
230 
231    public:
232     explicit ImplDisposer(const typename Cls::LocalRef& aInstance)
233         : Runnable("nsWindow::NativePtr::Detach"),
234           mInstance(aInstance.Env(), aInstance),
235           mOldImpl(aInstance
236                        ? jni::GetNativeHandle(aInstance.Env(), aInstance.Get())
237                        : 0) {
238       MOZ_CATCH_JNI_EXCEPTION(aInstance.Env());
239     }
240 
241     NS_IMETHOD Run() override {
242       if (!mInstance) {
243         return NS_OK;
244       }
245 
246       if (!NS_IsMainThread()) {
247         NS_DispatchToMainThread(this);
248         return NS_OK;
249       }
250 
251       typename Cls::LocalRef instance(jni::GetGeckoThreadEnv(), mInstance);
252       auto newImpl = jni::GetNativeHandle(instance.Env(), instance.Get());
253       MOZ_CATCH_JNI_EXCEPTION(instance.Env());
254 
255       if (mOldImpl == newImpl) {
256         // Only dispose the object if the native object has not changed.
257         Impl::DisposeNative(instance);
258       }
259       return NS_OK;
260     }
261   };
262 
263   // Objects that use nsWindow::NativePtr are expected to implement a public
264   // member function with signature "void OnDetach(
265   // already_AddRefed<Runnable> aDisposer)".  This function should perform
266   // necessary cleanups for the native/Java objects, as well as mark the Java
267   // object as being disposed, so no native methods are called after that
268   // point. After this disposal step, the function must call "aDisposer->
269   // Run()" to finish disposing the native object. The disposer is
270   // thread-safe and may be called on any thread as necessary.
271   mImpl->OnDetach(
272       do_AddRef(new ImplDisposer({jni::GetGeckoThreadEnv(), aInstance})));
273 
274   {
275     Locked implLock(*this);
276     mImpl = nullptr;
277   }
278 
279   typename WindowPtr<Impl>::Locked lock(*mPtr);
280   mPtr->mWindow = nullptr;
281   mPtr->mPtr = nullptr;
282   mPtr = nullptr;
283 }
284 
285 template <class Impl>
286 class nsWindow::NativePtr<Impl>::Locked final : private MutexAutoLock {
287   Impl* const mImpl;
288 
289  public:
Locked(NativePtr<Impl> & aPtr)290   explicit Locked(NativePtr<Impl>& aPtr)
291       : MutexAutoLock(aPtr.mImplLock), mImpl(aPtr.mImpl) {}
292 
operator Impl*() const293   operator Impl*() const { return mImpl; }
operator ->() const294   Impl* operator->() const { return mImpl; }
295 };
296 
297 class nsWindow::GeckoViewSupport final
298     : public GeckoSession::Window::Natives<GeckoViewSupport>,
299       public SupportsWeakPtr<GeckoViewSupport> {
300   nsWindow& window;
301 
302   // We hold a WeakRef because we want to allow the
303   // GeckoSession.Window to be garbage collected.
304   // Callers need to create a LocalRef from this
305   // before calling methods.
306   GeckoSession::Window::WeakRef mGeckoViewWindow;
307 
308  public:
309   typedef GeckoSession::Window::Natives<GeckoViewSupport> Base;
310   typedef SupportsWeakPtr<GeckoViewSupport> SupportsWeakPtr;
311 
312   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(GeckoViewSupport);
313 
314   template <typename Functor>
OnNativeCall(Functor && aCall)315   static void OnNativeCall(Functor&& aCall) {
316     NS_DispatchToMainThread(new WindowEvent<Functor>(std::move(aCall)));
317   }
318 
GeckoViewSupport(nsWindow * aWindow,const GeckoSession::Window::LocalRef & aInstance)319   GeckoViewSupport(nsWindow* aWindow,
320                    const GeckoSession::Window::LocalRef& aInstance)
321       : window(*aWindow), mGeckoViewWindow(aInstance) {
322     Base::AttachNative(aInstance, static_cast<SupportsWeakPtr*>(this));
323   }
324 
325   ~GeckoViewSupport();
326 
327   using Base::DisposeNative;
328 
329   /**
330    * GeckoView methods
331    */
332  private:
333   nsCOMPtr<nsPIDOMWindowOuter> mDOMWindow;
334   bool mIsReady{false};
335 
336  public:
337   // Create and attach a window.
338   static void Open(const jni::Class::LocalRef& aCls,
339                    GeckoSession::Window::Param aWindow,
340                    jni::Object::Param aQueue, jni::Object::Param aCompositor,
341                    jni::Object::Param aDispatcher,
342                    jni::Object::Param aSessionAccessibility,
343                    jni::Object::Param aInitData, jni::String::Param aId,
344                    jni::String::Param aChromeURI, int32_t aScreenId,
345                    bool aPrivateMode, bool aRemote);
346 
347   // Close and destroy the nsWindow.
348   void Close();
349 
350   // Transfer this nsWindow to new GeckoSession objects.
351   void Transfer(const GeckoSession::Window::LocalRef& inst,
352                 jni::Object::Param aQueue, jni::Object::Param aCompositor,
353                 jni::Object::Param aDispatcher,
354                 jni::Object::Param aSessionAccessibility,
355                 jni::Object::Param aInitData);
356 
357   void AttachEditable(const GeckoSession::Window::LocalRef& inst,
358                       jni::Object::Param aEditableParent);
359 
360   void AttachAccessibility(const GeckoSession::Window::LocalRef& inst,
361                            jni::Object::Param aSessionAccessibility);
362 
363   void OnReady(jni::Object::Param aQueue = nullptr);
364 
365   auto OnLoadRequest(mozilla::jni::String::Param aUri, int32_t aWindowType,
366                      int32_t aFlags, mozilla::jni::String::Param aTriggeringUri,
367                      bool aHasUserGesture, bool aIsTopLevel) const
368       -> java::GeckoResult::LocalRef;
369 };
370 
371 /**
372  * PanZoomController handles its native calls on the UI thread, so make
373  * it separate from GeckoViewSupport.
374  */
375 class nsWindow::NPZCSupport final
376     : public java::PanZoomController::NativeProvider::Natives<NPZCSupport> {
377   using LockedWindowPtr = WindowPtr<NPZCSupport>::Locked;
378 
379   WindowPtr<NPZCSupport> mWindow;
380   java::PanZoomController::NativeProvider::WeakRef mNPZC;
381   int mPreviousButtons;
382 
383   template <typename Lambda>
384   class InputEvent final : public nsAppShell::Event {
385     java::PanZoomController::NativeProvider::GlobalRef mNPZC;
386     Lambda mLambda;
387 
388    public:
InputEvent(const NPZCSupport * aNPZCSupport,Lambda && aLambda)389     InputEvent(const NPZCSupport* aNPZCSupport, Lambda&& aLambda)
390         : mNPZC(aNPZCSupport->mNPZC), mLambda(std::move(aLambda)) {}
391 
Run()392     void Run() override {
393       MOZ_ASSERT(NS_IsMainThread());
394 
395       JNIEnv* const env = jni::GetGeckoThreadEnv();
396       NPZCSupport* npzcSupport = GetNative(
397           java::PanZoomController::NativeProvider::LocalRef(env, mNPZC));
398 
399       if (!npzcSupport || !npzcSupport->mWindow) {
400         // We already shut down.
401         env->ExceptionClear();
402         return;
403       }
404 
405       nsWindow* const window = npzcSupport->mWindow;
406       window->UserActivity();
407       return mLambda(window);
408     }
409 
IsUIEvent() const410     bool IsUIEvent() const override { return true; }
411   };
412 
413   template <typename Lambda>
PostInputEvent(Lambda && aLambda)414   void PostInputEvent(Lambda&& aLambda) {
415     // Use priority queue for input events.
416     nsAppShell::PostEvent(
417         MakeUnique<InputEvent<Lambda>>(this, std::move(aLambda)));
418   }
419 
420  public:
421   typedef java::PanZoomController::NativeProvider::Natives<NPZCSupport> Base;
422 
NPZCSupport(NativePtr<NPZCSupport> * aPtr,nsWindow * aWindow,const java::PanZoomController::NativeProvider::LocalRef & aNPZC)423   NPZCSupport(NativePtr<NPZCSupport>* aPtr, nsWindow* aWindow,
424               const java::PanZoomController::NativeProvider::LocalRef& aNPZC)
425       : mWindow(aPtr, aWindow), mNPZC(aNPZC), mPreviousButtons(0) {
426     MOZ_ASSERT(mWindow);
427   }
428 
~NPZCSupport()429   ~NPZCSupport() {}
430 
431   using Base::AttachNative;
432   using Base::DisposeNative;
433 
OnDetach(already_AddRefed<Runnable> aDisposer)434   void OnDetach(already_AddRefed<Runnable> aDisposer) {
435     RefPtr<Runnable> disposer = aDisposer;
436     // There are several considerations when shutting down NPZC. 1) The
437     // Gecko thread may destroy NPZC at any time when nsWindow closes. 2)
438     // There may be pending events on the Gecko thread when NPZC is
439     // destroyed. 3) mWindow may not be available when the pending event
440     // runs. 4) The UI thread may destroy NPZC at any time when GeckoView
441     // is destroyed. 5) The UI thread may destroy NPZC at the same time as
442     // Gecko thread trying to destroy NPZC. 6) There may be pending calls
443     // on the UI thread when NPZC is destroyed. 7) mWindow may have been
444     // cleared on the Gecko thread when the pending call happens on the UI
445     // thread.
446     //
447     // 1) happens through OnDetach, which first notifies the UI
448     // thread through Destroy; Destroy then calls DisposeNative, which
449     // finally disposes the native instance back on the Gecko thread. Using
450     // Destroy to indirectly call DisposeNative here also solves 5), by
451     // making everything go through the UI thread, avoiding contention.
452     //
453     // 2) and 3) are solved by clearing mWindow, which signals to the
454     // pending event that we had shut down. In that case the event bails
455     // and does not touch mWindow.
456     //
457     // 4) happens through DisposeNative directly. OnDetach is not
458     // called.
459     //
460     // 6) is solved by keeping a destroyed flag in the Java NPZC instance,
461     // and only make a pending call if the destroyed flag is not set.
462     //
463     // 7) is solved by taking a lock whenever mWindow is modified on the
464     // Gecko thread or accessed on the UI thread. That way, we don't
465     // release mWindow until the UI thread is done using it, thus avoiding
466     // the race condition.
467 
468     if (RefPtr<nsThread> uiThread = GetAndroidUiThread()) {
469       auto npzc = java::PanZoomController::NativeProvider::GlobalRef(mNPZC);
470       if (!npzc) {
471         return;
472       }
473 
474       uiThread->Dispatch(NS_NewRunnableFunction(
475           "NPZCSupport::OnDetach", [npzc, disposer = std::move(disposer)] {
476             npzc->SetAttached(false);
477             disposer->Run();
478           }));
479     }
480   }
481 
GetJavaNPZC() const482   const java::PanZoomController::NativeProvider::Ref& GetJavaNPZC() const {
483     return mNPZC;
484   }
485 
486  public:
SetIsLongpressEnabled(bool aIsLongpressEnabled)487   void SetIsLongpressEnabled(bool aIsLongpressEnabled) {
488     RefPtr<IAPZCTreeManager> controller;
489 
490     if (LockedWindowPtr window{mWindow}) {
491       controller = window->mAPZC;
492     }
493 
494     if (controller) {
495       controller->SetLongTapEnabled(aIsLongpressEnabled);
496     }
497   }
498 
HandleScrollEvent(int64_t aTime,int32_t aMetaState,float aX,float aY,float aHScroll,float aVScroll)499   int32_t HandleScrollEvent(int64_t aTime, int32_t aMetaState, float aX,
500                             float aY, float aHScroll, float aVScroll) {
501     MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
502 
503     RefPtr<IAPZCTreeManager> controller;
504 
505     if (LockedWindowPtr window{mWindow}) {
506       controller = window->mAPZC;
507     }
508 
509     if (!controller) {
510       return INPUT_RESULT_UNHANDLED;
511     }
512 
513     ScreenPoint origin = ScreenPoint(aX, aY);
514 
515     if (StaticPrefs::ui_scrolling_negate_wheel_scroll()) {
516       aHScroll = -aHScroll;
517       aVScroll = -aVScroll;
518     }
519 
520     ScrollWheelInput input(
521         aTime, GetEventTimeStamp(aTime), GetModifiers(aMetaState),
522         ScrollWheelInput::SCROLLMODE_SMOOTH,
523         ScrollWheelInput::SCROLLDELTA_PIXEL, origin, aHScroll, aVScroll, false,
524         // XXX Do we need to support auto-dir scrolling
525         // for Android widgets with a wheel device?
526         // Currently, I just leave it unimplemented. If
527         // we need to implement it, what's the extra work
528         // to do?
529         WheelDeltaAdjustmentStrategy::eNone);
530 
531     APZEventResult result = controller->InputBridge()->ReceiveInputEvent(input);
532     int32_t ret =
533         !result.mTargetIsRoot || result.mHitRegionWithApzAwareListeners
534             ? INPUT_RESULT_HANDLED_CONTENT
535             : INPUT_RESULT_HANDLED;
536 
537     if (result.mStatus == nsEventStatus_eConsumeNoDefault) {
538       return ret;
539     }
540 
541     PostInputEvent([input, result](nsWindow* window) {
542       WidgetWheelEvent wheelEvent = input.ToWidgetWheelEvent(window);
543       window->ProcessUntransformedAPZEvent(&wheelEvent, result);
544     });
545 
546     switch (result.mStatus) {
547       case nsEventStatus_eIgnore:
548         return INPUT_RESULT_UNHANDLED;
549       case nsEventStatus_eConsumeDoDefault:
550         return ret;
551       default:
552         MOZ_ASSERT_UNREACHABLE("Unexpected nsEventStatus");
553         return INPUT_RESULT_UNHANDLED;
554     }
555   }
556 
557  private:
GetButtonType(int button)558   static MouseInput::ButtonType GetButtonType(int button) {
559     MouseInput::ButtonType result = MouseInput::NONE;
560 
561     switch (button) {
562       case java::sdk::MotionEvent::BUTTON_PRIMARY:
563         result = MouseInput::LEFT_BUTTON;
564         break;
565       case java::sdk::MotionEvent::BUTTON_SECONDARY:
566         result = MouseInput::RIGHT_BUTTON;
567         break;
568       case java::sdk::MotionEvent::BUTTON_TERTIARY:
569         result = MouseInput::MIDDLE_BUTTON;
570         break;
571       default:
572         break;
573     }
574 
575     return result;
576   }
577 
ConvertButtons(int buttons)578   static int16_t ConvertButtons(int buttons) {
579     int16_t result = 0;
580 
581     if (buttons & java::sdk::MotionEvent::BUTTON_PRIMARY) {
582       result |= MouseButtonsFlag::eLeftFlag;
583     }
584     if (buttons & java::sdk::MotionEvent::BUTTON_SECONDARY) {
585       result |= MouseButtonsFlag::eRightFlag;
586     }
587     if (buttons & java::sdk::MotionEvent::BUTTON_TERTIARY) {
588       result |= MouseButtonsFlag::eMiddleFlag;
589     }
590     if (buttons & java::sdk::MotionEvent::BUTTON_BACK) {
591       result |= MouseButtonsFlag::e4thFlag;
592     }
593     if (buttons & java::sdk::MotionEvent::BUTTON_FORWARD) {
594       result |= MouseButtonsFlag::e5thFlag;
595     }
596 
597     return result;
598   }
599 
600  public:
HandleMouseEvent(int32_t aAction,int64_t aTime,int32_t aMetaState,float aX,float aY,int buttons)601   int32_t HandleMouseEvent(int32_t aAction, int64_t aTime, int32_t aMetaState,
602                            float aX, float aY, int buttons) {
603     MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
604 
605     RefPtr<IAPZCTreeManager> controller;
606 
607     if (LockedWindowPtr window{mWindow}) {
608       controller = window->mAPZC;
609     }
610 
611     if (!controller) {
612       return INPUT_RESULT_UNHANDLED;
613     }
614 
615     MouseInput::MouseType mouseType = MouseInput::MOUSE_NONE;
616     MouseInput::ButtonType buttonType = MouseInput::NONE;
617     switch (aAction) {
618       case java::sdk::MotionEvent::ACTION_DOWN:
619         mouseType = MouseInput::MOUSE_DOWN;
620         buttonType = GetButtonType(buttons ^ mPreviousButtons);
621         mPreviousButtons = buttons;
622         break;
623       case java::sdk::MotionEvent::ACTION_UP:
624         mouseType = MouseInput::MOUSE_UP;
625         buttonType = GetButtonType(buttons ^ mPreviousButtons);
626         mPreviousButtons = buttons;
627         break;
628       case java::sdk::MotionEvent::ACTION_MOVE:
629         mouseType = MouseInput::MOUSE_MOVE;
630         break;
631       case java::sdk::MotionEvent::ACTION_HOVER_MOVE:
632         mouseType = MouseInput::MOUSE_MOVE;
633         break;
634       case java::sdk::MotionEvent::ACTION_HOVER_ENTER:
635         mouseType = MouseInput::MOUSE_WIDGET_ENTER;
636         break;
637       case java::sdk::MotionEvent::ACTION_HOVER_EXIT:
638         mouseType = MouseInput::MOUSE_WIDGET_EXIT;
639         break;
640       default:
641         break;
642     }
643 
644     if (mouseType == MouseInput::MOUSE_NONE) {
645       return INPUT_RESULT_UNHANDLED;
646     }
647 
648     ScreenPoint origin = ScreenPoint(aX, aY);
649 
650     MouseInput input(mouseType, buttonType,
651                      MouseEvent_Binding::MOZ_SOURCE_MOUSE,
652                      ConvertButtons(buttons), origin, aTime,
653                      GetEventTimeStamp(aTime), GetModifiers(aMetaState));
654 
655     APZEventResult result = controller->InputBridge()->ReceiveInputEvent(input);
656     int32_t ret =
657         !result.mTargetIsRoot || result.mHitRegionWithApzAwareListeners
658             ? INPUT_RESULT_HANDLED_CONTENT
659             : INPUT_RESULT_HANDLED;
660 
661     if (result.mStatus == nsEventStatus_eConsumeNoDefault) {
662       return ret;
663     }
664 
665     PostInputEvent([input, result](nsWindow* window) {
666       WidgetMouseEvent mouseEvent = input.ToWidgetMouseEvent(window);
667       window->ProcessUntransformedAPZEvent(&mouseEvent, result);
668     });
669 
670     switch (result.mStatus) {
671       case nsEventStatus_eIgnore:
672         return INPUT_RESULT_UNHANDLED;
673       case nsEventStatus_eConsumeDoDefault:
674         return ret;
675       default:
676         MOZ_ASSERT_UNREACHABLE("Unexpected nsEventStatus");
677         return INPUT_RESULT_UNHANDLED;
678     }
679   }
680 
HandleMotionEvent(const java::PanZoomController::NativeProvider::LocalRef & aInstance,int32_t aAction,int32_t aActionIndex,int64_t aTime,int32_t aMetaState,float aScreenX,float aScreenY,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)681   int32_t HandleMotionEvent(
682       const java::PanZoomController::NativeProvider::LocalRef& aInstance,
683       int32_t aAction, int32_t aActionIndex, int64_t aTime, int32_t aMetaState,
684       float aScreenX, float aScreenY, jni::IntArray::Param aPointerId,
685       jni::FloatArray::Param aX, jni::FloatArray::Param aY,
686       jni::FloatArray::Param aOrientation, jni::FloatArray::Param aPressure,
687       jni::FloatArray::Param aToolMajor, jni::FloatArray::Param aToolMinor) {
688     MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
689 
690     RefPtr<IAPZCTreeManager> controller;
691 
692     if (LockedWindowPtr window{mWindow}) {
693       controller = window->mAPZC;
694     }
695 
696     if (!controller) {
697       return INPUT_RESULT_UNHANDLED;
698     }
699 
700     nsTArray<int32_t> pointerId(aPointerId->GetElements());
701     MultiTouchInput::MultiTouchType type;
702     size_t startIndex = 0;
703     size_t endIndex = pointerId.Length();
704 
705     switch (aAction) {
706       case java::sdk::MotionEvent::ACTION_DOWN:
707       case java::sdk::MotionEvent::ACTION_POINTER_DOWN:
708         type = MultiTouchInput::MULTITOUCH_START;
709         break;
710       case java::sdk::MotionEvent::ACTION_MOVE:
711         type = MultiTouchInput::MULTITOUCH_MOVE;
712         break;
713       case java::sdk::MotionEvent::ACTION_UP:
714       case java::sdk::MotionEvent::ACTION_POINTER_UP:
715         // for pointer-up events we only want the data from
716         // the one pointer that went up
717         type = MultiTouchInput::MULTITOUCH_END;
718         startIndex = aActionIndex;
719         endIndex = aActionIndex + 1;
720         break;
721       case java::sdk::MotionEvent::ACTION_OUTSIDE:
722       case java::sdk::MotionEvent::ACTION_CANCEL:
723         type = MultiTouchInput::MULTITOUCH_CANCEL;
724         break;
725       default:
726         return INPUT_RESULT_UNHANDLED;
727     }
728 
729     MultiTouchInput input(type, aTime, GetEventTimeStamp(aTime), 0);
730     input.modifiers = GetModifiers(aMetaState);
731     input.mTouches.SetCapacity(endIndex - startIndex);
732     input.mScreenOffset =
733         ExternalIntPoint(int32_t(floorf(aScreenX)), int32_t(floorf(aScreenY)));
734 
735     nsTArray<float> x(aX->GetElements());
736     nsTArray<float> y(aY->GetElements());
737     nsTArray<float> orientation(aOrientation->GetElements());
738     nsTArray<float> pressure(aPressure->GetElements());
739     nsTArray<float> toolMajor(aToolMajor->GetElements());
740     nsTArray<float> toolMinor(aToolMinor->GetElements());
741 
742     MOZ_ASSERT(pointerId.Length() == x.Length());
743     MOZ_ASSERT(pointerId.Length() == y.Length());
744     MOZ_ASSERT(pointerId.Length() == orientation.Length());
745     MOZ_ASSERT(pointerId.Length() == pressure.Length());
746     MOZ_ASSERT(pointerId.Length() == toolMajor.Length());
747     MOZ_ASSERT(pointerId.Length() == toolMinor.Length());
748 
749     for (size_t i = startIndex; i < endIndex; i++) {
750       float orien = orientation[i] * 180.0f / M_PI;
751       // w3c touchevents spec does not allow orientations == 90
752       // this shifts it to -90, which will be shifted to zero below
753       if (orien >= 90.0) {
754         orien -= 180.0f;
755       }
756 
757       nsIntPoint point =
758           nsIntPoint(int32_t(floorf(x[i])), int32_t(floorf(y[i])));
759 
760       // w3c touchevent radii are given with an orientation between 0 and
761       // 90. The radii are found by removing the orientation and
762       // measuring the x and y radii of the resulting ellipse. For
763       // Android orientations >= 0 and < 90, use the y radius as the
764       // major radius, and x as the minor radius. However, for an
765       // orientation < 0, we have to shift the orientation by adding 90,
766       // and reverse which radius is major and minor.
767       gfx::Size radius;
768       if (orien < 0.0f) {
769         orien += 90.0f;
770         radius = gfx::Size(int32_t(toolMajor[i] / 2.0f),
771                            int32_t(toolMinor[i] / 2.0f));
772       } else {
773         radius = gfx::Size(int32_t(toolMinor[i] / 2.0f),
774                            int32_t(toolMajor[i] / 2.0f));
775       }
776 
777       input.mTouches.AppendElement(SingleTouchData(
778           pointerId[i], ScreenIntPoint::FromUnknownPoint(point),
779           ScreenSize::FromUnknownSize(radius), orien, pressure[i]));
780     }
781 
782     APZEventResult result = controller->InputBridge()->ReceiveInputEvent(input);
783     int32_t ret =
784         !result.mTargetIsRoot || result.mHitRegionWithApzAwareListeners
785             ? INPUT_RESULT_HANDLED_CONTENT
786             : INPUT_RESULT_HANDLED;
787 
788     if (result.mStatus == nsEventStatus_eConsumeNoDefault) {
789       return ret;
790     }
791 
792     // Dispatch APZ input event on Gecko thread.
793     PostInputEvent([input, result](nsWindow* window) {
794       WidgetTouchEvent touchEvent = input.ToWidgetTouchEvent(window);
795       window->ProcessUntransformedAPZEvent(&touchEvent, result);
796       window->DispatchHitTest(touchEvent);
797     });
798 
799     switch (result.mStatus) {
800       case nsEventStatus_eIgnore:
801         return INPUT_RESULT_UNHANDLED;
802       case nsEventStatus_eConsumeDoDefault:
803         return ret;
804       default:
805         MOZ_ASSERT_UNREACHABLE("Unexpected nsEventStatus");
806         return INPUT_RESULT_UNHANDLED;
807     }
808   }
809 };
810 
811 template <>
812 const char nsWindow::NativePtr<nsWindow::NPZCSupport>::sName[] = "NPZCSupport";
813 
NS_IMPL_ISUPPORTS(nsWindow::AndroidView,nsIAndroidEventDispatcher,nsIAndroidView)814 NS_IMPL_ISUPPORTS(nsWindow::AndroidView, nsIAndroidEventDispatcher,
815                   nsIAndroidView)
816 
817 nsresult nsWindow::AndroidView::GetInitData(JSContext* aCx,
818                                             JS::MutableHandleValue aOut) {
819   if (!mInitData) {
820     aOut.setNull();
821     return NS_OK;
822   }
823 
824   return widget::EventDispatcher::UnboxBundle(aCx, mInitData, aOut);
825 }
826 
827 /**
828  * Compositor has some unique requirements for its native calls, so make it
829  * separate from GeckoViewSupport.
830  */
831 class nsWindow::LayerViewSupport final
832     : public GeckoSession::Compositor::Natives<LayerViewSupport> {
833   using LockedWindowPtr = WindowPtr<LayerViewSupport>::Locked;
834 
835   WindowPtr<LayerViewSupport> mWindow;
836   GeckoSession::Compositor::WeakRef mCompositor;
837   Atomic<bool, ReleaseAcquire> mCompositorPaused;
838   jni::Object::GlobalRef mSurface;
839 
840   struct CaptureRequest {
CaptureRequestnsWindow::LayerViewSupport::CaptureRequest841     explicit CaptureRequest() : mResult(nullptr) {}
CaptureRequestnsWindow::LayerViewSupport::CaptureRequest842     explicit CaptureRequest(java::GeckoResult::GlobalRef aResult,
843                             const ScreenRect& aSource,
844                             const IntSize& aOutputSize)
845         : mResult(aResult), mSource(aSource), mOutputSize(aOutputSize) {}
846 
847     // where to send the pixels
848     java::GeckoResult::GlobalRef mResult;
849 
850     ScreenRect mSource;
851 
852     IntSize mOutputSize;
853   };
854   std::queue<CaptureRequest> mCapturePixelsResults;
855 
856   // In order to use Event::HasSameTypeAs in PostTo(), we cannot make
857   // LayerViewEvent a template because each template instantiation is
858   // a different type. So implement LayerViewEvent as a ProxyEvent.
859   class LayerViewEvent final : public nsAppShell::ProxyEvent {
860     using Event = nsAppShell::Event;
861 
862    public:
MakeEvent(UniquePtr<Event> && event)863     static UniquePtr<Event> MakeEvent(UniquePtr<Event>&& event) {
864       return MakeUnique<LayerViewEvent>(std::move(event));
865     }
866 
LayerViewEvent(UniquePtr<Event> && event)867     explicit LayerViewEvent(UniquePtr<Event>&& event)
868         : nsAppShell::ProxyEvent(std::move(event)) {}
869 
PostTo(LinkedList<Event> & queue)870     void PostTo(LinkedList<Event>& queue) override {
871       // Give priority to compositor events, but keep in order with
872       // existing compositor events.
873       nsAppShell::Event* event = queue.getFirst();
874       while (event && event->HasSameTypeAs(this)) {
875         event = event->getNext();
876       }
877       if (event) {
878         event->setPrevious(this);
879       } else {
880         queue.insertBack(this);
881       }
882     }
883   };
884 
885  public:
886   typedef GeckoSession::Compositor::Natives<LayerViewSupport> Base;
887 
FromNative(const GeckoSession::Compositor::LocalRef & instance)888   static LayerViewSupport* FromNative(
889       const GeckoSession::Compositor::LocalRef& instance) {
890     return GetNative(instance);
891   }
892 
LayerViewSupport(NativePtr<LayerViewSupport> * aPtr,nsWindow * aWindow,const GeckoSession::Compositor::LocalRef & aInstance)893   LayerViewSupport(NativePtr<LayerViewSupport>* aPtr, nsWindow* aWindow,
894                    const GeckoSession::Compositor::LocalRef& aInstance)
895       : mWindow(aPtr, aWindow),
896         mCompositor(aInstance),
897         mCompositorPaused(true) {
898     MOZ_ASSERT(mWindow);
899   }
900 
~LayerViewSupport()901   ~LayerViewSupport() {}
902 
903   using Base::AttachNative;
904   using Base::DisposeNative;
905 
OnDetach(already_AddRefed<Runnable> aDisposer)906   void OnDetach(already_AddRefed<Runnable> aDisposer) {
907     RefPtr<Runnable> disposer = aDisposer;
908     if (RefPtr<nsThread> uiThread = GetAndroidUiThread()) {
909       GeckoSession::Compositor::GlobalRef compositor(mCompositor);
910       if (!compositor) {
911         return;
912       }
913 
914       uiThread->Dispatch(NS_NewRunnableFunction(
915           "LayerViewSupport::OnDetach",
916           [compositor, disposer = std::move(disposer),
917            results = &mCapturePixelsResults, window = &mWindow] {
918             if (LockedWindowPtr lock{*window}) {
919               while (!results->empty()) {
920                 auto aResult =
921                     java::GeckoResult::LocalRef(results->front().mResult);
922                 if (aResult) {
923                   aResult->CompleteExceptionally(
924                       java::sdk::IllegalStateException::New(
925                           "The compositor has detached from the session")
926                           .Cast<jni::Throwable>());
927                   results->pop();
928                 }
929               }
930               compositor->OnCompositorDetached();
931               disposer->Run();
932             }
933           }));
934     }
935   }
936 
GetJavaCompositor() const937   const GeckoSession::Compositor::Ref& GetJavaCompositor() const {
938     return mCompositor;
939   }
940 
CompositorPaused() const941   bool CompositorPaused() const { return mCompositorPaused; }
942 
GetSurface()943   jni::Object::Param GetSurface() { return mSurface; }
944 
945  private:
946   already_AddRefed<UiCompositorControllerChild>
GetUiCompositorControllerChild()947   GetUiCompositorControllerChild() {
948     RefPtr<UiCompositorControllerChild> child;
949     if (LockedWindowPtr window{mWindow}) {
950       child = window->GetUiCompositorControllerChild();
951     }
952     return child.forget();
953   }
954 
FlipScreenPixels(Shmem & aMem,const ScreenIntSize & aInSize,const ScreenRect & aInRegion,const IntSize & aOutSize)955   int8_t* FlipScreenPixels(Shmem& aMem, const ScreenIntSize& aInSize,
956                            const ScreenRect& aInRegion,
957                            const IntSize& aOutSize) {
958     RefPtr<DataSourceSurface> image = gfx::CreateDataSourceSurfaceFromData(
959         IntSize(aInSize.width, aInSize.height), SurfaceFormat::B8G8R8A8,
960         aMem.get<uint8_t>(),
961         StrideForFormatAndWidth(SurfaceFormat::B8G8R8A8, aInSize.width));
962     RefPtr<DrawTarget> drawTarget =
963         gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
964             aOutSize, SurfaceFormat::B8G8R8A8);
965     drawTarget->SetTransform(Matrix::Scaling(1.0, -1.0) *
966                              Matrix::Translation(0, aOutSize.height));
967 
968     gfx::Rect srcRect(aInRegion.x,
969                       (aInSize.height - aInRegion.height) - aInRegion.y,
970                       aInRegion.width, aInRegion.height);
971     gfx::Rect destRect(0, 0, aOutSize.width, aOutSize.height);
972     drawTarget->DrawSurface(image, destRect, srcRect);
973 
974     RefPtr<SourceSurface> snapshot = drawTarget->Snapshot();
975     RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
976     DataSourceSurface::ScopedMap* smap =
977         new DataSourceSurface::ScopedMap(data, DataSourceSurface::READ);
978     return reinterpret_cast<int8_t*>(smap->GetData());
979   }
980 
981   /**
982    * Compositor methods
983    */
984  public:
AttachNPZC(jni::Object::Param aNPZC)985   void AttachNPZC(jni::Object::Param aNPZC) {
986     MOZ_ASSERT(NS_IsMainThread());
987     if (!mWindow) {
988       return;  // Already shut down.
989     }
990 
991     MOZ_ASSERT(aNPZC);
992 
993     // We can have this situation if we get two GeckoViewSupport::Transfer()
994     // called before the first AttachNPZC() gets here. Just detach the current
995     // instance since that's what happens in GeckoViewSupport::Transfer() as
996     // well.
997     if (mWindow->mNPZCSupport) {
998       mWindow->mNPZCSupport.Detach(mWindow->mNPZCSupport->GetJavaNPZC());
999     }
1000 
1001     auto npzc = java::PanZoomController::NativeProvider::LocalRef(
1002         jni::GetGeckoThreadEnv(),
1003         java::PanZoomController::NativeProvider::Ref::From(aNPZC));
1004     mWindow->mNPZCSupport.Attach(npzc, mWindow, npzc);
1005 
1006     DispatchToUiThread(
1007         "LayerViewSupport::AttachNPZC",
1008         [npzc = java::PanZoomController::NativeProvider::GlobalRef(npzc)] {
1009           npzc->SetAttached(true);
1010         });
1011   }
1012 
OnBoundsChanged(int32_t aLeft,int32_t aTop,int32_t aWidth,int32_t aHeight)1013   void OnBoundsChanged(int32_t aLeft, int32_t aTop, int32_t aWidth,
1014                        int32_t aHeight) {
1015     MOZ_ASSERT(NS_IsMainThread());
1016     if (!mWindow) {
1017       return;  // Already shut down.
1018     }
1019 
1020     mWindow->Resize(aLeft, aTop, aWidth, aHeight, /* repaint */ false);
1021   }
1022 
SetDynamicToolbarMaxHeight(int32_t aHeight)1023   void SetDynamicToolbarMaxHeight(int32_t aHeight) {
1024     MOZ_ASSERT(NS_IsMainThread());
1025     if (!mWindow) {
1026       return;  // Already shut down.
1027     }
1028 
1029     mWindow->UpdateDynamicToolbarMaxHeight(ScreenIntCoord(aHeight));
1030   }
1031 
SyncPauseCompositor()1032   void SyncPauseCompositor() {
1033     MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
1034 
1035     if (RefPtr<UiCompositorControllerChild> child =
1036             GetUiCompositorControllerChild()) {
1037       mCompositorPaused = true;
1038       child->Pause();
1039     }
1040   }
1041 
SyncResumeCompositor()1042   void SyncResumeCompositor() {
1043     MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
1044 
1045     if (RefPtr<UiCompositorControllerChild> child =
1046             GetUiCompositorControllerChild()) {
1047       mCompositorPaused = false;
1048       child->Resume();
1049     }
1050   }
1051 
SyncResumeResizeCompositor(const GeckoSession::Compositor::LocalRef & aObj,int32_t aX,int32_t aY,int32_t aWidth,int32_t aHeight,jni::Object::Param aSurface)1052   void SyncResumeResizeCompositor(
1053       const GeckoSession::Compositor::LocalRef& aObj, int32_t aX, int32_t aY,
1054       int32_t aWidth, int32_t aHeight, jni::Object::Param aSurface) {
1055     MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
1056 
1057     mSurface = aSurface;
1058 
1059     if (RefPtr<UiCompositorControllerChild> child =
1060             GetUiCompositorControllerChild()) {
1061       child->ResumeAndResize(aX, aY, aWidth, aHeight);
1062     }
1063 
1064     mCompositorPaused = false;
1065 
1066     class OnResumedEvent : public nsAppShell::Event {
1067       GeckoSession::Compositor::GlobalRef mCompositor;
1068 
1069      public:
1070       explicit OnResumedEvent(GeckoSession::Compositor::GlobalRef&& aCompositor)
1071           : mCompositor(std::move(aCompositor)) {}
1072 
1073       void Run() override {
1074         MOZ_ASSERT(NS_IsMainThread());
1075 
1076         JNIEnv* const env = jni::GetGeckoThreadEnv();
1077         LayerViewSupport* const lvs =
1078             GetNative(GeckoSession::Compositor::LocalRef(env, mCompositor));
1079 
1080         if (!lvs || !lvs->mWindow) {
1081           env->ExceptionClear();
1082           return;  // Already shut down.
1083         }
1084 
1085         // When we get here, the compositor has already been told to
1086         // resume. This means it's now safe for layer updates to occur.
1087         // Since we might have prevented one or more draw events from
1088         // occurring while the compositor was paused, we need to
1089         // schedule a draw event now.
1090         if (!lvs->mCompositorPaused) {
1091           lvs->mWindow->RedrawAll();
1092         }
1093       }
1094     };
1095 
1096     // Use priority queue for timing-sensitive event.
1097     nsAppShell::PostEvent(
1098         MakeUnique<LayerViewEvent>(MakeUnique<OnResumedEvent>(aObj)));
1099   }
1100 
SyncInvalidateAndScheduleComposite()1101   void SyncInvalidateAndScheduleComposite() {
1102     RefPtr<UiCompositorControllerChild> child =
1103         GetUiCompositorControllerChild();
1104     if (!child) {
1105       return;
1106     }
1107 
1108     if (AndroidBridge::IsJavaUiThread()) {
1109       child->InvalidateAndRender();
1110       return;
1111     }
1112 
1113     if (RefPtr<nsThread> uiThread = GetAndroidUiThread()) {
1114       uiThread->Dispatch(NewRunnableMethod<>(
1115                              "LayerViewSupport::InvalidateAndRender", child,
1116                              &UiCompositorControllerChild::InvalidateAndRender),
1117                          nsIThread::DISPATCH_NORMAL);
1118     }
1119   }
1120 
SetMaxToolbarHeight(int32_t aHeight)1121   void SetMaxToolbarHeight(int32_t aHeight) {
1122     MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
1123 
1124     if (RefPtr<UiCompositorControllerChild> child =
1125             GetUiCompositorControllerChild()) {
1126       child->SetMaxToolbarHeight(aHeight);
1127     }
1128   }
1129 
SetFixedBottomOffset(int32_t aOffset)1130   void SetFixedBottomOffset(int32_t aOffset) {
1131     if (mWindow) {
1132       mWindow->UpdateDynamicToolbarOffset(ScreenIntCoord(aOffset));
1133     }
1134 
1135     if (RefPtr<nsThread> uiThread = GetAndroidUiThread()) {
1136       uiThread->Dispatch(NS_NewRunnableFunction(
1137           "LayerViewSupport::SetFixedBottomOffset", [this, offset = aOffset] {
1138             if (RefPtr<UiCompositorControllerChild> child =
1139                     GetUiCompositorControllerChild()) {
1140               child->SetFixedBottomOffset(offset);
1141             }
1142           }));
1143     }
1144   }
1145 
SendToolbarAnimatorMessage(int32_t aMessage)1146   void SendToolbarAnimatorMessage(int32_t aMessage) {
1147     RefPtr<UiCompositorControllerChild> child =
1148         GetUiCompositorControllerChild();
1149     if (!child) {
1150       return;
1151     }
1152 
1153     if (AndroidBridge::IsJavaUiThread()) {
1154       child->ToolbarAnimatorMessageFromUI(aMessage);
1155       return;
1156     }
1157 
1158     if (RefPtr<nsThread> uiThread = GetAndroidUiThread()) {
1159       uiThread->Dispatch(
1160           NewRunnableMethod<int32_t>(
1161               "LayerViewSupport::ToolbarAnimatorMessageFromUI", child,
1162               &UiCompositorControllerChild::ToolbarAnimatorMessageFromUI,
1163               aMessage),
1164           nsIThread::DISPATCH_NORMAL);
1165     }
1166   }
1167 
RecvToolbarAnimatorMessage(int32_t aMessage)1168   void RecvToolbarAnimatorMessage(int32_t aMessage) {
1169     auto compositor = GeckoSession::Compositor::LocalRef(mCompositor);
1170     if (compositor) {
1171       compositor->RecvToolbarAnimatorMessage(aMessage);
1172     }
1173   }
1174 
SetDefaultClearColor(int32_t aColor)1175   void SetDefaultClearColor(int32_t aColor) {
1176     MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
1177     if (RefPtr<UiCompositorControllerChild> child =
1178             GetUiCompositorControllerChild()) {
1179       child->SetDefaultClearColor((uint32_t)aColor);
1180     }
1181   }
1182 
RequestScreenPixels(jni::Object::Param aResult,int32_t aXOffset,int32_t aYOffset,int32_t aSrcWidth,int32_t aSrcHeight,int32_t aOutWidth,int32_t aOutHeight)1183   void RequestScreenPixels(jni::Object::Param aResult, int32_t aXOffset,
1184                            int32_t aYOffset, int32_t aSrcWidth,
1185                            int32_t aSrcHeight, int32_t aOutWidth,
1186                            int32_t aOutHeight) {
1187     MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
1188 
1189     int size = 0;
1190     if (LockedWindowPtr window{mWindow}) {
1191       mCapturePixelsResults.push(CaptureRequest(
1192           java::GeckoResult::GlobalRef(java::GeckoResult::LocalRef(aResult)),
1193           ScreenRect(aXOffset, aYOffset, aSrcWidth, aSrcHeight),
1194           IntSize(aOutWidth, aOutHeight)));
1195       size = mCapturePixelsResults.size();
1196     }
1197 
1198     if (size == 1) {
1199       if (RefPtr<UiCompositorControllerChild> child =
1200               GetUiCompositorControllerChild()) {
1201         child->RequestScreenPixels();
1202       }
1203     }
1204   }
1205 
RecvScreenPixels(Shmem && aMem,const ScreenIntSize & aSize)1206   void RecvScreenPixels(Shmem&& aMem, const ScreenIntSize& aSize) {
1207     MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
1208     CaptureRequest aCaptureRequest;
1209     java::GeckoResult::LocalRef aResult = nullptr;
1210     if (LockedWindowPtr window{mWindow}) {
1211       aCaptureRequest = mCapturePixelsResults.front();
1212       aResult = java::GeckoResult::LocalRef(aCaptureRequest.mResult);
1213       if (aResult) {
1214         mCapturePixelsResults.pop();
1215       }
1216     }
1217 
1218     if (aResult) {
1219       auto pixels = mozilla::jni::ByteBuffer::New(
1220           FlipScreenPixels(aMem, aSize, aCaptureRequest.mSource,
1221                            aCaptureRequest.mOutputSize),
1222           aMem.Size<int8_t>());
1223       aResult->Complete(pixels);
1224     }
1225 
1226     // Pixels have been copied, so Dealloc Shmem
1227     if (RefPtr<UiCompositorControllerChild> child =
1228             GetUiCompositorControllerChild()) {
1229       child->DeallocPixelBuffer(aMem);
1230 
1231       if (LockedWindowPtr window{mWindow}) {
1232         if (!mCapturePixelsResults.empty()) {
1233           child->RequestScreenPixels();
1234         }
1235       }
1236     }
1237   }
1238 
EnableLayerUpdateNotifications(bool aEnable)1239   void EnableLayerUpdateNotifications(bool aEnable) {
1240     MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
1241     if (RefPtr<UiCompositorControllerChild> child =
1242             GetUiCompositorControllerChild()) {
1243       child->EnableLayerUpdateNotifications(aEnable);
1244     }
1245   }
1246 
OnSafeAreaInsetsChanged(int32_t aTop,int32_t aRight,int32_t aBottom,int32_t aLeft)1247   void OnSafeAreaInsetsChanged(int32_t aTop, int32_t aRight, int32_t aBottom,
1248                                int32_t aLeft) {
1249     MOZ_ASSERT(NS_IsMainThread());
1250     if (!mWindow) {
1251       return;  // Already shut down.
1252     }
1253     ScreenIntMargin safeAreaInsets(aTop, aRight, aBottom, aLeft);
1254     mWindow->UpdateSafeAreaInsets(safeAreaInsets);
1255   }
1256 };
1257 
1258 template <>
1259 const char nsWindow::NativePtr<nsWindow::LayerViewSupport>::sName[] =
1260     "LayerViewSupport";
1261 
~GeckoViewSupport()1262 nsWindow::GeckoViewSupport::~GeckoViewSupport() {
1263   // Disassociate our GeckoEditable instance with our native object.
1264   if (window.mEditableSupport) {
1265     window.mEditableSupport.Detach(window.mEditableSupport->GetJavaEditable());
1266     window.mEditableParent = nullptr;
1267   }
1268 
1269   if (window.mNPZCSupport) {
1270     window.mNPZCSupport.Detach(window.mNPZCSupport->GetJavaNPZC());
1271   }
1272 
1273   if (window.mLayerViewSupport) {
1274     window.mLayerViewSupport.Detach(
1275         window.mLayerViewSupport->GetJavaCompositor());
1276   }
1277 
1278   if (window.mSessionAccessibility) {
1279     window.mSessionAccessibility.Detach(
1280         window.mSessionAccessibility->GetJavaAccessibility());
1281   }
1282 }
1283 
1284 /* static */
Open(const jni::Class::LocalRef & aCls,GeckoSession::Window::Param aWindow,jni::Object::Param aQueue,jni::Object::Param aCompositor,jni::Object::Param aDispatcher,jni::Object::Param aSessionAccessibility,jni::Object::Param aInitData,jni::String::Param aId,jni::String::Param aChromeURI,int32_t aScreenId,bool aPrivateMode,bool aRemote)1285 void nsWindow::GeckoViewSupport::Open(
1286     const jni::Class::LocalRef& aCls, GeckoSession::Window::Param aWindow,
1287     jni::Object::Param aQueue, jni::Object::Param aCompositor,
1288     jni::Object::Param aDispatcher, jni::Object::Param aSessionAccessibility,
1289     jni::Object::Param aInitData, jni::String::Param aId,
1290     jni::String::Param aChromeURI, int32_t aScreenId, bool aPrivateMode,
1291     bool aRemote) {
1292   MOZ_ASSERT(NS_IsMainThread());
1293 
1294   AUTO_PROFILER_LABEL("nsWindow::GeckoViewSupport::Open", OTHER);
1295 
1296   nsCOMPtr<nsIWindowWatcher> ww = do_GetService(NS_WINDOWWATCHER_CONTRACTID);
1297   MOZ_RELEASE_ASSERT(ww);
1298 
1299   nsAutoCString url;
1300   if (aChromeURI) {
1301     url = aChromeURI->ToCString();
1302   } else {
1303     nsresult rv = Preferences::GetCString("toolkit.defaultChromeURI", url);
1304     if (NS_FAILED(rv)) {
1305       url = NS_LITERAL_CSTRING("chrome://geckoview/content/geckoview.xhtml");
1306     }
1307   }
1308 
1309   // Prepare an nsIAndroidView to pass as argument to the window.
1310   RefPtr<AndroidView> androidView = new AndroidView();
1311   androidView->mEventDispatcher->Attach(
1312       java::EventDispatcher::Ref::From(aDispatcher), nullptr);
1313   androidView->mInitData = java::GeckoBundle::Ref::From(aInitData);
1314 
1315   nsAutoCString chromeFlags("chrome,dialog=0,resizable,scrollbars");
1316   if (aPrivateMode) {
1317     chromeFlags += ",private";
1318   }
1319   if (aRemote) {
1320     chromeFlags += ",remote";
1321   }
1322   nsCOMPtr<mozIDOMWindowProxy> domWindow;
1323   ww->OpenWindow(nullptr, url.get(), aId->ToCString().get(), chromeFlags.get(),
1324                  androidView, getter_AddRefs(domWindow));
1325   MOZ_RELEASE_ASSERT(domWindow);
1326 
1327   nsCOMPtr<nsPIDOMWindowOuter> pdomWindow = nsPIDOMWindowOuter::From(domWindow);
1328   const RefPtr<nsWindow> window = nsWindow::From(pdomWindow);
1329   MOZ_ASSERT(window);
1330   window->SetScreenId(aScreenId);
1331 
1332   // Attach a new GeckoView support object to the new window.
1333   GeckoSession::Window::LocalRef sessionWindow(aCls.Env(), aWindow);
1334   window->mGeckoViewSupport =
1335       mozilla::MakeUnique<GeckoViewSupport>(window, sessionWindow);
1336   window->mGeckoViewSupport->mDOMWindow = pdomWindow;
1337   window->mAndroidView = androidView;
1338 
1339   // Attach other session support objects.
1340   window->mGeckoViewSupport->Transfer(sessionWindow, aQueue, aCompositor,
1341                                       aDispatcher, aSessionAccessibility,
1342                                       aInitData);
1343 
1344   if (window->mWidgetListener) {
1345     nsCOMPtr<nsIAppWindow> appWindow(window->mWidgetListener->GetAppWindow());
1346     if (appWindow) {
1347       // Our window is not intrinsically sized, so tell AppWindow to
1348       // not set a size for us.
1349       appWindow->SetIntrinsicallySized(false);
1350     }
1351   }
1352 }
1353 
Close()1354 void nsWindow::GeckoViewSupport::Close() {
1355   if (window.mAndroidView) {
1356     window.mAndroidView->mEventDispatcher->Detach();
1357   }
1358 
1359   if (!mDOMWindow) {
1360     return;
1361   }
1362 
1363   mDOMWindow->ForceClose();
1364   mDOMWindow = nullptr;
1365   mGeckoViewWindow = nullptr;
1366 }
1367 
Transfer(const GeckoSession::Window::LocalRef & inst,jni::Object::Param aQueue,jni::Object::Param aCompositor,jni::Object::Param aDispatcher,jni::Object::Param aSessionAccessibility,jni::Object::Param aInitData)1368 void nsWindow::GeckoViewSupport::Transfer(
1369     const GeckoSession::Window::LocalRef& inst, jni::Object::Param aQueue,
1370     jni::Object::Param aCompositor, jni::Object::Param aDispatcher,
1371     jni::Object::Param aSessionAccessibility, jni::Object::Param aInitData) {
1372   if (window.mNPZCSupport) {
1373     MOZ_ASSERT(window.mLayerViewSupport);
1374     window.mNPZCSupport.Detach(window.mNPZCSupport->GetJavaNPZC());
1375   }
1376 
1377   auto compositor = GeckoSession::Compositor::LocalRef(
1378       inst.Env(), GeckoSession::Compositor::Ref::From(aCompositor));
1379   if (window.mLayerViewSupport &&
1380       window.mLayerViewSupport->GetJavaCompositor() != compositor) {
1381     window.mLayerViewSupport.Detach(
1382         window.mLayerViewSupport->GetJavaCompositor());
1383   }
1384   if (!window.mLayerViewSupport) {
1385     window.mLayerViewSupport.Attach(compositor, &window, compositor);
1386   }
1387 
1388   MOZ_ASSERT(window.mAndroidView);
1389   window.mAndroidView->mEventDispatcher->Attach(
1390       java::EventDispatcher::Ref::From(aDispatcher), mDOMWindow);
1391 
1392   if (window.mSessionAccessibility) {
1393     window.mSessionAccessibility.Detach(
1394         window.mSessionAccessibility->GetJavaAccessibility());
1395   }
1396   if (aSessionAccessibility) {
1397     AttachAccessibility(inst, aSessionAccessibility);
1398   }
1399 
1400   if (mIsReady) {
1401     // We're in a transfer; update init-data and notify JS code.
1402     window.mAndroidView->mInitData = java::GeckoBundle::Ref::From(aInitData);
1403     OnReady(aQueue);
1404     window.mAndroidView->mEventDispatcher->Dispatch(
1405         u"GeckoView:UpdateInitData");
1406   }
1407 
1408   DispatchToUiThread("GeckoViewSupport::Transfer",
1409                      [compositor = GeckoSession::Compositor::GlobalRef(
1410                           compositor)] { compositor->OnCompositorAttached(); });
1411 }
1412 
AttachEditable(const GeckoSession::Window::LocalRef & inst,jni::Object::Param aEditableParent)1413 void nsWindow::GeckoViewSupport::AttachEditable(
1414     const GeckoSession::Window::LocalRef& inst,
1415     jni::Object::Param aEditableParent) {
1416   if (!window.mEditableSupport) {
1417     auto editableChild = java::GeckoEditableChild::New(aEditableParent,
1418                                                        /* default */ true);
1419     window.mEditableSupport.Attach(editableChild, &window, editableChild);
1420   } else {
1421     window.mEditableSupport->TransferParent(aEditableParent);
1422   }
1423 
1424   window.mEditableParent = aEditableParent;
1425 }
1426 
AttachAccessibility(const GeckoSession::Window::LocalRef & inst,jni::Object::Param aSessionAccessibility)1427 void nsWindow::GeckoViewSupport::AttachAccessibility(
1428     const GeckoSession::Window::LocalRef& inst,
1429     jni::Object::Param aSessionAccessibility) {
1430   MOZ_ASSERT(!window.mSessionAccessibility);
1431   java::SessionAccessibility::NativeProvider::LocalRef sessionAccessibility(
1432       inst.Env());
1433   sessionAccessibility = java::SessionAccessibility::NativeProvider::Ref::From(
1434       aSessionAccessibility);
1435 
1436   if (window.mSessionAccessibility) {
1437     window.mSessionAccessibility.Detach(
1438         window.mSessionAccessibility->GetJavaAccessibility());
1439   }
1440 
1441   window.mSessionAccessibility.Attach(sessionAccessibility, &window,
1442                                       sessionAccessibility);
1443 }
1444 
InitNatives()1445 void nsWindow::InitNatives() {
1446   jni::InitConversionStatics();
1447   nsWindow::GeckoViewSupport::Base::Init();
1448   nsWindow::LayerViewSupport::Init();
1449   nsWindow::NPZCSupport::Init();
1450 
1451   GeckoEditableSupport::Init();
1452   a11y::SessionAccessibility::Init();
1453 }
1454 
1455 /* static */
From(nsPIDOMWindowOuter * aDOMWindow)1456 already_AddRefed<nsWindow> nsWindow::From(nsPIDOMWindowOuter* aDOMWindow) {
1457   nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(aDOMWindow);
1458   return From(widget);
1459 }
1460 
1461 /* static */
From(nsIWidget * aWidget)1462 already_AddRefed<nsWindow> nsWindow::From(nsIWidget* aWidget) {
1463   // `widget` may be one of several different types in the parent
1464   // process, including the Android nsWindow, PuppetWidget, etc. To
1465   // ensure that the cast to the Android nsWindow is valid, we check that the
1466   // widget is a top-level window and that its NS_NATIVE_WIDGET value is
1467   // non-null, which is not the case for non-native widgets like
1468   // PuppetWidget.
1469   if (aWidget && aWidget->WindowType() == nsWindowType::eWindowType_toplevel &&
1470       aWidget->GetNativeData(NS_NATIVE_WIDGET) == aWidget) {
1471     RefPtr<nsWindow> window = static_cast<nsWindow*>(aWidget);
1472     return window.forget();
1473   }
1474   return nullptr;
1475 }
1476 
TopWindow()1477 nsWindow* nsWindow::TopWindow() {
1478   if (!gTopLevelWindows.IsEmpty()) return gTopLevelWindows[0];
1479   return nullptr;
1480 }
1481 
LogWindow(nsWindow * win,int index,int indent)1482 void nsWindow::LogWindow(nsWindow* win, int index, int indent) {
1483 #if defined(DEBUG) || defined(FORCE_ALOG)
1484   char spaces[] = "                    ";
1485   spaces[indent < 20 ? indent : 20] = 0;
1486   ALOG("%s [% 2d] 0x%p [parent 0x%p] [% 3d,% 3dx% 3d,% 3d] vis %d type %d",
1487        spaces, index, win, win->mParent, win->mBounds.x, win->mBounds.y,
1488        win->mBounds.width, win->mBounds.height, win->mIsVisible,
1489        win->mWindowType);
1490 #endif
1491 }
1492 
DumpWindows()1493 void nsWindow::DumpWindows() { DumpWindows(gTopLevelWindows); }
1494 
DumpWindows(const nsTArray<nsWindow * > & wins,int indent)1495 void nsWindow::DumpWindows(const nsTArray<nsWindow*>& wins, int indent) {
1496   for (uint32_t i = 0; i < wins.Length(); ++i) {
1497     nsWindow* w = wins[i];
1498     LogWindow(w, i, indent);
1499     DumpWindows(w->mChildren, indent + 1);
1500   }
1501 }
1502 
nsWindow()1503 nsWindow::nsWindow()
1504     : mScreenId(0),  // Use 0 (primary screen) as the default value.
1505       mIsVisible(false),
1506       mParent(nullptr),
1507       mDynamicToolbarMaxHeight(0),
1508       mIsFullScreen(false),
1509       mIsDisablingWebRender(false) {}
1510 
~nsWindow()1511 nsWindow::~nsWindow() {
1512   gTopLevelWindows.RemoveElement(this);
1513   ALOG("nsWindow %p destructor", (void*)this);
1514   // The mCompositorSession should have been cleaned up in nsWindow::Destroy()
1515   // DestroyLayerManager() will call DestroyCompositor() which will crash if
1516   // called from nsBaseWidget destructor. See Bug 1392705
1517   MOZ_ASSERT(!mCompositorSession);
1518 }
1519 
IsTopLevel()1520 bool nsWindow::IsTopLevel() {
1521   return mWindowType == eWindowType_toplevel ||
1522          mWindowType == eWindowType_dialog ||
1523          mWindowType == eWindowType_invisible;
1524 }
1525 
Create(nsIWidget * aParent,nsNativeWidget aNativeParent,const LayoutDeviceIntRect & aRect,nsWidgetInitData * aInitData)1526 nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
1527                           const LayoutDeviceIntRect& aRect,
1528                           nsWidgetInitData* aInitData) {
1529   ALOG("nsWindow[%p]::Create %p [%d %d %d %d]", (void*)this, (void*)aParent,
1530        aRect.x, aRect.y, aRect.width, aRect.height);
1531 
1532   nsWindow* parent = (nsWindow*)aParent;
1533   if (aNativeParent) {
1534     if (parent) {
1535       ALOG(
1536           "Ignoring native parent on Android window [%p], "
1537           "since parent was specified (%p %p)",
1538           (void*)this, (void*)aNativeParent, (void*)aParent);
1539     } else {
1540       parent = (nsWindow*)aNativeParent;
1541     }
1542   }
1543 
1544   // A default size of 1x1 confuses MobileViewportManager, so
1545   // use 0x0 instead. This is also a little more fitting since
1546   // we don't yet have a surface yet (and therefore a valid size)
1547   // and 0x0 is usually recognized as invalid.
1548   LayoutDeviceIntRect rect = aRect;
1549   if (aRect.width == 1 && aRect.height == 1) {
1550     rect.width = 0;
1551     rect.height = 0;
1552   }
1553 
1554   mBounds = rect;
1555 
1556   BaseCreate(nullptr, aInitData);
1557 
1558   NS_ASSERTION(IsTopLevel() || parent,
1559                "non-top-level window doesn't have a parent!");
1560 
1561   if (IsTopLevel()) {
1562     gTopLevelWindows.AppendElement(this);
1563 
1564   } else if (parent) {
1565     parent->mChildren.AppendElement(this);
1566     mParent = parent;
1567   }
1568 
1569   CreateLayerManager();
1570 
1571 #ifdef DEBUG_ANDROID_WIDGET
1572   DumpWindows();
1573 #endif
1574 
1575   return NS_OK;
1576 }
1577 
Destroy()1578 void nsWindow::Destroy() {
1579   nsBaseWidget::mOnDestroyCalled = true;
1580 
1581   if (mGeckoViewSupport) {
1582     // Disassociate our native object with GeckoView.
1583     mGeckoViewSupport = nullptr;
1584   }
1585 
1586   // Stuff below may release the last ref to this
1587   nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1588 
1589   while (mChildren.Length()) {
1590     // why do we still have children?
1591     ALOG("### Warning: Destroying window %p and reparenting child %p to null!",
1592          (void*)this, (void*)mChildren[0]);
1593     mChildren[0]->SetParent(nullptr);
1594   }
1595 
1596   // Ensure the compositor has been shutdown before this nsWindow is potentially
1597   // deleted
1598   nsBaseWidget::DestroyCompositor();
1599 
1600   nsBaseWidget::Destroy();
1601 
1602   if (IsTopLevel()) gTopLevelWindows.RemoveElement(this);
1603 
1604   SetParent(nullptr);
1605 
1606   nsBaseWidget::OnDestroy();
1607 
1608 #ifdef DEBUG_ANDROID_WIDGET
1609   DumpWindows();
1610 #endif
1611 }
1612 
ConfigureChildren(const nsTArray<nsIWidget::Configuration> & config)1613 nsresult nsWindow::ConfigureChildren(
1614     const nsTArray<nsIWidget::Configuration>& config) {
1615   for (uint32_t i = 0; i < config.Length(); ++i) {
1616     nsWindow* childWin = (nsWindow*)config[i].mChild.get();
1617     childWin->Resize(config[i].mBounds.x, config[i].mBounds.y,
1618                      config[i].mBounds.width, config[i].mBounds.height, false);
1619   }
1620 
1621   return NS_OK;
1622 }
1623 
RedrawAll()1624 void nsWindow::RedrawAll() {
1625   if (mAttachedWidgetListener) {
1626     mAttachedWidgetListener->RequestRepaint();
1627   } else if (mWidgetListener) {
1628     mWidgetListener->RequestRepaint();
1629   }
1630 }
1631 
GetUiCompositorControllerChild()1632 RefPtr<UiCompositorControllerChild> nsWindow::GetUiCompositorControllerChild() {
1633   return mCompositorSession
1634              ? mCompositorSession->GetUiCompositorControllerChild()
1635              : nullptr;
1636 }
1637 
GetRootLayerId() const1638 mozilla::layers::LayersId nsWindow::GetRootLayerId() const {
1639   return mCompositorSession ? mCompositorSession->RootLayerTreeId()
1640                             : mozilla::layers::LayersId{0};
1641 }
1642 
OnGeckoViewReady()1643 void nsWindow::OnGeckoViewReady() {
1644   if (!mGeckoViewSupport) {
1645     return;
1646   }
1647   mGeckoViewSupport->OnReady();
1648 }
1649 
SetParent(nsIWidget * aNewParent)1650 void nsWindow::SetParent(nsIWidget* aNewParent) {
1651   if ((nsIWidget*)mParent == aNewParent) return;
1652 
1653   // If we had a parent before, remove ourselves from its list of
1654   // children.
1655   if (mParent) mParent->mChildren.RemoveElement(this);
1656 
1657   mParent = (nsWindow*)aNewParent;
1658 
1659   if (mParent) mParent->mChildren.AppendElement(this);
1660 
1661   // if we are now in the toplevel window's hierarchy, schedule a redraw
1662   if (FindTopLevel() == nsWindow::TopWindow()) RedrawAll();
1663 }
1664 
GetParent()1665 nsIWidget* nsWindow::GetParent() { return mParent; }
1666 
OnLoadRequest(nsIURI * aUri,int32_t aWindowType,int32_t aFlags,nsIPrincipal * aTriggeringPrincipal,bool aHasUserGesture,bool aIsTopLevel)1667 RefPtr<MozPromise<bool, bool, false>> nsWindow::OnLoadRequest(
1668     nsIURI* aUri, int32_t aWindowType, int32_t aFlags,
1669     nsIPrincipal* aTriggeringPrincipal, bool aHasUserGesture,
1670     bool aIsTopLevel) {
1671   if (!mGeckoViewSupport) {
1672     return MozPromise<bool, bool, false>::CreateAndResolve(false, __func__);
1673   }
1674   nsAutoCString spec, triggeringSpec;
1675   if (aUri) {
1676     aUri->GetDisplaySpec(spec);
1677   }
1678 
1679   bool isNullPrincipal = false;
1680   if (aTriggeringPrincipal) {
1681     aTriggeringPrincipal->GetIsNullPrincipal(&isNullPrincipal);
1682 
1683     if (!isNullPrincipal) {
1684       nsCOMPtr<nsIURI> triggeringUri;
1685       BasePrincipal::Cast(aTriggeringPrincipal)
1686           ->GetURI(getter_AddRefs(triggeringUri));
1687       if (triggeringUri) {
1688         triggeringUri->GetDisplaySpec(triggeringSpec);
1689       }
1690     }
1691   }
1692 
1693   auto geckoResult = mGeckoViewSupport->OnLoadRequest(
1694       spec.get(), aWindowType, aFlags,
1695       isNullPrincipal ? nullptr : triggeringSpec.get(), aHasUserGesture,
1696       aIsTopLevel);
1697   return geckoResult
1698              ? MozPromise<bool, bool, false>::FromGeckoResult(geckoResult)
1699              : nullptr;
1700 }
1701 
GetDPI()1702 float nsWindow::GetDPI() {
1703   float dpi = 160.0f;
1704 
1705   nsCOMPtr<nsIScreen> screen = GetWidgetScreen();
1706   if (screen) {
1707     screen->GetDpi(&dpi);
1708   }
1709 
1710   return dpi;
1711 }
1712 
GetDefaultScaleInternal()1713 double nsWindow::GetDefaultScaleInternal() {
1714   double scale = 1.0f;
1715 
1716   nsCOMPtr<nsIScreen> screen = GetWidgetScreen();
1717   if (screen) {
1718     screen->GetContentsScaleFactor(&scale);
1719   }
1720 
1721   return scale;
1722 }
1723 
Show(bool aState)1724 void nsWindow::Show(bool aState) {
1725   ALOG("nsWindow[%p]::Show %d", (void*)this, aState);
1726 
1727   if (mWindowType == eWindowType_invisible) {
1728     ALOG("trying to show invisible window! ignoring..");
1729     return;
1730   }
1731 
1732   if (aState == mIsVisible) return;
1733 
1734   mIsVisible = aState;
1735 
1736   if (IsTopLevel()) {
1737     // XXX should we bring this to the front when it's shown,
1738     // if it's a toplevel widget?
1739 
1740     // XXX we should synthesize a eMouseExitFromWidget (for old top
1741     // window)/eMouseEnterIntoWidget (for new top window) since we need
1742     // to pretend that the top window always has focus.  Not sure
1743     // if Show() is the right place to do this, though.
1744 
1745     if (aState) {
1746       // It just became visible, so bring it to the front.
1747       BringToFront();
1748 
1749     } else if (nsWindow::TopWindow() == this) {
1750       // find the next visible window to show
1751       unsigned int i;
1752       for (i = 1; i < gTopLevelWindows.Length(); i++) {
1753         nsWindow* win = gTopLevelWindows[i];
1754         if (!win->mIsVisible) continue;
1755 
1756         win->BringToFront();
1757         break;
1758       }
1759     }
1760   } else if (FindTopLevel() == nsWindow::TopWindow()) {
1761     RedrawAll();
1762   }
1763 
1764 #ifdef DEBUG_ANDROID_WIDGET
1765   DumpWindows();
1766 #endif
1767 }
1768 
IsVisible() const1769 bool nsWindow::IsVisible() const { return mIsVisible; }
1770 
ConstrainPosition(bool aAllowSlop,int32_t * aX,int32_t * aY)1771 void nsWindow::ConstrainPosition(bool aAllowSlop, int32_t* aX, int32_t* aY) {
1772   ALOG("nsWindow[%p]::ConstrainPosition %d [%d %d]", (void*)this, aAllowSlop,
1773        *aX, *aY);
1774 
1775   // constrain toplevel windows; children we don't care about
1776   if (IsTopLevel()) {
1777     *aX = 0;
1778     *aY = 0;
1779   }
1780 }
1781 
Move(double aX,double aY)1782 void nsWindow::Move(double aX, double aY) {
1783   if (IsTopLevel()) return;
1784 
1785   Resize(aX, aY, mBounds.width, mBounds.height, true);
1786 }
1787 
Resize(double aWidth,double aHeight,bool aRepaint)1788 void nsWindow::Resize(double aWidth, double aHeight, bool aRepaint) {
1789   Resize(mBounds.x, mBounds.y, aWidth, aHeight, aRepaint);
1790 }
1791 
Resize(double aX,double aY,double aWidth,double aHeight,bool aRepaint)1792 void nsWindow::Resize(double aX, double aY, double aWidth, double aHeight,
1793                       bool aRepaint) {
1794   ALOG("nsWindow[%p]::Resize [%f %f %f %f] (repaint %d)", (void*)this, aX, aY,
1795        aWidth, aHeight, aRepaint);
1796 
1797   bool needPositionDispatch = aX != mBounds.x || aY != mBounds.y;
1798   bool needSizeDispatch = aWidth != mBounds.width || aHeight != mBounds.height;
1799 
1800   mBounds.x = NSToIntRound(aX);
1801   mBounds.y = NSToIntRound(aY);
1802   mBounds.width = NSToIntRound(aWidth);
1803   mBounds.height = NSToIntRound(aHeight);
1804 
1805   if (needSizeDispatch) {
1806     OnSizeChanged(gfx::IntSize::Truncate(aWidth, aHeight));
1807   }
1808 
1809   if (needPositionDispatch) {
1810     NotifyWindowMoved(mBounds.x, mBounds.y);
1811   }
1812 
1813   // Should we skip honoring aRepaint here?
1814   if (aRepaint && FindTopLevel() == nsWindow::TopWindow()) RedrawAll();
1815 }
1816 
SetZIndex(int32_t aZIndex)1817 void nsWindow::SetZIndex(int32_t aZIndex) {
1818   ALOG("nsWindow[%p]::SetZIndex %d ignored", (void*)this, aZIndex);
1819 }
1820 
SetSizeMode(nsSizeMode aMode)1821 void nsWindow::SetSizeMode(nsSizeMode aMode) {
1822   if (aMode == mSizeMode) {
1823     return;
1824   }
1825 
1826   nsBaseWidget::SetSizeMode(aMode);
1827 
1828   switch (aMode) {
1829     case nsSizeMode_Minimized:
1830       java::GeckoAppShell::MoveTaskToBack();
1831       break;
1832     case nsSizeMode_Fullscreen:
1833       MakeFullScreen(true);
1834       break;
1835     default:
1836       break;
1837   }
1838 }
1839 
Enable(bool aState)1840 void nsWindow::Enable(bool aState) {
1841   ALOG("nsWindow[%p]::Enable %d ignored", (void*)this, aState);
1842 }
1843 
IsEnabled() const1844 bool nsWindow::IsEnabled() const { return true; }
1845 
Invalidate(const LayoutDeviceIntRect & aRect)1846 void nsWindow::Invalidate(const LayoutDeviceIntRect& aRect) {}
1847 
FindTopLevel()1848 nsWindow* nsWindow::FindTopLevel() {
1849   nsWindow* toplevel = this;
1850   while (toplevel) {
1851     if (toplevel->IsTopLevel()) return toplevel;
1852 
1853     toplevel = toplevel->mParent;
1854   }
1855 
1856   ALOG(
1857       "nsWindow::FindTopLevel(): couldn't find a toplevel or dialog window in "
1858       "this [%p] widget's hierarchy!",
1859       (void*)this);
1860   return this;
1861 }
1862 
SetFocus(Raise,mozilla::dom::CallerType aCallerType)1863 void nsWindow::SetFocus(Raise, mozilla::dom::CallerType aCallerType) {
1864   FindTopLevel()->BringToFront();
1865 }
1866 
BringToFront()1867 void nsWindow::BringToFront() {
1868   MOZ_ASSERT(XRE_IsParentProcess());
1869   // If the window to be raised is the same as the currently raised one,
1870   // do nothing. We need to check the focus manager as well, as the first
1871   // window that is created will be first in the window list but won't yet
1872   // be focused.
1873   nsFocusManager* fm = nsFocusManager::GetFocusManager();
1874   if (fm && fm->GetActiveWindow() && FindTopLevel() == nsWindow::TopWindow()) {
1875     return;
1876   }
1877 
1878   if (!IsTopLevel()) {
1879     FindTopLevel()->BringToFront();
1880     return;
1881   }
1882 
1883   RefPtr<nsWindow> kungFuDeathGrip(this);
1884 
1885   nsWindow* oldTop = nullptr;
1886   if (!gTopLevelWindows.IsEmpty()) {
1887     oldTop = gTopLevelWindows[0];
1888   }
1889 
1890   gTopLevelWindows.RemoveElement(this);
1891   gTopLevelWindows.InsertElementAt(0, this);
1892 
1893   if (oldTop) {
1894     nsIWidgetListener* listener = oldTop->GetWidgetListener();
1895     if (listener) {
1896       listener->WindowDeactivated();
1897     }
1898   }
1899 
1900   if (mWidgetListener) {
1901     mWidgetListener->WindowActivated();
1902   }
1903 
1904   RedrawAll();
1905 }
1906 
GetScreenBounds()1907 LayoutDeviceIntRect nsWindow::GetScreenBounds() {
1908   return LayoutDeviceIntRect(WidgetToScreenOffset(), mBounds.Size());
1909 }
1910 
WidgetToScreenOffset()1911 LayoutDeviceIntPoint nsWindow::WidgetToScreenOffset() {
1912   LayoutDeviceIntPoint p(0, 0);
1913 
1914   for (nsWindow* w = this; !!w; w = w->mParent) {
1915     p.x += w->mBounds.x;
1916     p.y += w->mBounds.y;
1917 
1918     if (w->IsTopLevel()) {
1919       break;
1920     }
1921   }
1922   return p;
1923 }
1924 
DispatchEvent(WidgetGUIEvent * aEvent,nsEventStatus & aStatus)1925 nsresult nsWindow::DispatchEvent(WidgetGUIEvent* aEvent,
1926                                  nsEventStatus& aStatus) {
1927   aStatus = DispatchEvent(aEvent);
1928   return NS_OK;
1929 }
1930 
DispatchEvent(WidgetGUIEvent * aEvent)1931 nsEventStatus nsWindow::DispatchEvent(WidgetGUIEvent* aEvent) {
1932   if (mAttachedWidgetListener) {
1933     return mAttachedWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
1934   } else if (mWidgetListener) {
1935     return mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
1936   }
1937   return nsEventStatus_eIgnore;
1938 }
1939 
MakeFullScreen(bool aFullScreen,nsIScreen *)1940 nsresult nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen*) {
1941   if (!mAndroidView) {
1942     return NS_ERROR_NOT_AVAILABLE;
1943   }
1944 
1945   mIsFullScreen = aFullScreen;
1946   mAndroidView->mEventDispatcher->Dispatch(
1947       aFullScreen ? u"GeckoView:FullScreenEnter" : u"GeckoView:FullScreenExit");
1948 
1949   nsIWidgetListener* listener = GetWidgetListener();
1950   if (listener) {
1951     mSizeMode = mIsFullScreen ? nsSizeMode_Fullscreen : nsSizeMode_Normal;
1952     listener->SizeModeChanged(mSizeMode);
1953     listener->FullscreenChanged(mIsFullScreen);
1954   }
1955   return NS_OK;
1956 }
1957 
GetLayerManager(PLayerTransactionChild *,LayersBackend,LayerManagerPersistence)1958 mozilla::layers::LayerManager* nsWindow::GetLayerManager(
1959     PLayerTransactionChild*, LayersBackend, LayerManagerPersistence) {
1960   if (mLayerManager) {
1961     return mLayerManager;
1962   }
1963 
1964   if (mIsDisablingWebRender) {
1965     CreateLayerManager();
1966     mIsDisablingWebRender = false;
1967     return mLayerManager;
1968   }
1969 
1970   return nullptr;
1971 }
1972 
CreateLayerManager()1973 void nsWindow::CreateLayerManager() {
1974   if (mLayerManager) {
1975     return;
1976   }
1977 
1978   nsWindow* topLevelWindow = FindTopLevel();
1979   if (!topLevelWindow || topLevelWindow->mWindowType == eWindowType_invisible) {
1980     // don't create a layer manager for an invisible top-level window
1981     return;
1982   }
1983 
1984   // Ensure that gfxPlatform is initialized first.
1985   gfxPlatform::GetPlatform();
1986 
1987   if (ShouldUseOffMainThreadCompositing()) {
1988     LayoutDeviceIntRect rect = GetBounds();
1989     CreateCompositor(rect.Width(), rect.Height());
1990     if (mLayerManager) {
1991       return;
1992     }
1993 
1994     // If we get here, then off main thread compositing failed to initialize.
1995     sFailedToCreateGLContext = true;
1996   }
1997 
1998   if (!ComputeShouldAccelerate() || sFailedToCreateGLContext) {
1999     printf_stderr(" -- creating basic, not accelerated\n");
2000     mLayerManager = CreateBasicLayerManager();
2001   }
2002 }
2003 
NotifyDisablingWebRender()2004 void nsWindow::NotifyDisablingWebRender() {
2005   mIsDisablingWebRender = true;
2006   RedrawAll();
2007 }
2008 
OnSizeChanged(const gfx::IntSize & aSize)2009 void nsWindow::OnSizeChanged(const gfx::IntSize& aSize) {
2010   ALOG("nsWindow: %p OnSizeChanged [%d %d]", (void*)this, aSize.width,
2011        aSize.height);
2012 
2013   mBounds.width = aSize.width;
2014   mBounds.height = aSize.height;
2015 
2016   if (mWidgetListener) {
2017     mWidgetListener->WindowResized(this, aSize.width, aSize.height);
2018   }
2019 
2020   if (mAttachedWidgetListener) {
2021     mAttachedWidgetListener->WindowResized(this, aSize.width, aSize.height);
2022   }
2023 }
2024 
InitEvent(WidgetGUIEvent & event,LayoutDeviceIntPoint * aPoint)2025 void nsWindow::InitEvent(WidgetGUIEvent& event, LayoutDeviceIntPoint* aPoint) {
2026   if (aPoint) {
2027     event.mRefPoint = *aPoint;
2028   } else {
2029     event.mRefPoint = LayoutDeviceIntPoint(0, 0);
2030   }
2031 
2032   event.mTime = PR_Now() / 1000;
2033 }
2034 
UpdateOverscrollVelocity(const float aX,const float aY)2035 void nsWindow::UpdateOverscrollVelocity(const float aX, const float aY) {
2036   if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
2037     const auto& compositor = lvs->GetJavaCompositor();
2038     if (AndroidBridge::IsJavaUiThread()) {
2039       compositor->UpdateOverscrollVelocity(aX, aY);
2040       return;
2041     }
2042 
2043     DispatchToUiThread(
2044         "nsWindow::UpdateOverscrollVelocity",
2045         [compositor = GeckoSession::Compositor::GlobalRef(compositor), aX, aY] {
2046           compositor->UpdateOverscrollVelocity(aX, aY);
2047         });
2048   }
2049 }
2050 
UpdateOverscrollOffset(const float aX,const float aY)2051 void nsWindow::UpdateOverscrollOffset(const float aX, const float aY) {
2052   if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
2053     const auto& compositor = lvs->GetJavaCompositor();
2054     if (AndroidBridge::IsJavaUiThread()) {
2055       compositor->UpdateOverscrollOffset(aX, aY);
2056       return;
2057     }
2058 
2059     DispatchToUiThread(
2060         "nsWindow::UpdateOverscrollOffset",
2061         [compositor = GeckoSession::Compositor::GlobalRef(compositor), aX, aY] {
2062           compositor->UpdateOverscrollOffset(aX, aY);
2063         });
2064   }
2065 }
2066 
GetNativeData(uint32_t aDataType)2067 void* nsWindow::GetNativeData(uint32_t aDataType) {
2068   switch (aDataType) {
2069     // used by GLContextProviderEGL, nullptr is EGL_DEFAULT_DISPLAY
2070     case NS_NATIVE_DISPLAY:
2071       return nullptr;
2072 
2073     case NS_NATIVE_WIDGET:
2074       return (void*)this;
2075 
2076     case NS_RAW_NATIVE_IME_CONTEXT: {
2077       void* pseudoIMEContext = GetPseudoIMEContext();
2078       if (pseudoIMEContext) {
2079         return pseudoIMEContext;
2080       }
2081       // We assume that there is only one context per process on Android
2082       return NS_ONLY_ONE_NATIVE_IME_CONTEXT;
2083     }
2084 
2085     case NS_JAVA_SURFACE:
2086       if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
2087         return lvs->GetSurface().Get();
2088       }
2089       return nullptr;
2090   }
2091 
2092   return nullptr;
2093 }
2094 
SetNativeData(uint32_t aDataType,uintptr_t aVal)2095 void nsWindow::SetNativeData(uint32_t aDataType, uintptr_t aVal) {
2096   switch (aDataType) {}
2097 }
2098 
DispatchHitTest(const WidgetTouchEvent & aEvent)2099 void nsWindow::DispatchHitTest(const WidgetTouchEvent& aEvent) {
2100   if (aEvent.mMessage == eTouchStart && aEvent.mTouches.Length() == 1) {
2101     // Since touch events don't get retargeted by PositionedEventTargeting.cpp
2102     // code, we dispatch a dummy mouse event that *does* get retargeted.
2103     // Front-end code can use this to activate the highlight element in case
2104     // this touchstart is the start of a tap.
2105     WidgetMouseEvent hittest(true, eMouseHitTest, this,
2106                              WidgetMouseEvent::eReal);
2107     hittest.mRefPoint = aEvent.mTouches[0]->mRefPoint;
2108     hittest.mInputSource = MouseEvent_Binding::MOZ_SOURCE_TOUCH;
2109     nsEventStatus status;
2110     DispatchEvent(&hittest, status);
2111   }
2112 }
2113 
GetModifiers(int32_t metaState)2114 mozilla::Modifiers nsWindow::GetModifiers(int32_t metaState) {
2115   using mozilla::java::sdk::KeyEvent;
2116   return (metaState & KeyEvent::META_ALT_MASK ? MODIFIER_ALT : 0) |
2117          (metaState & KeyEvent::META_SHIFT_MASK ? MODIFIER_SHIFT : 0) |
2118          (metaState & KeyEvent::META_CTRL_MASK ? MODIFIER_CONTROL : 0) |
2119          (metaState & KeyEvent::META_META_MASK ? MODIFIER_META : 0) |
2120          (metaState & KeyEvent::META_FUNCTION_ON ? MODIFIER_FN : 0) |
2121          (metaState & KeyEvent::META_CAPS_LOCK_ON ? MODIFIER_CAPSLOCK : 0) |
2122          (metaState & KeyEvent::META_NUM_LOCK_ON ? MODIFIER_NUMLOCK : 0) |
2123          (metaState & KeyEvent::META_SCROLL_LOCK_ON ? MODIFIER_SCROLLLOCK : 0);
2124 }
2125 
GetEventTimeStamp(int64_t aEventTime)2126 TimeStamp nsWindow::GetEventTimeStamp(int64_t aEventTime) {
2127   // Android's event time is SystemClock.uptimeMillis that is counted in ms
2128   // since OS was booted.
2129   // (https://developer.android.com/reference/android/os/SystemClock.html)
2130   // and this SystemClock.uptimeMillis uses SYSTEM_TIME_MONOTONIC.
2131   // Our posix implemententaion of TimeStamp::Now uses SYSTEM_TIME_MONOTONIC
2132   //  too. Due to same implementation, we can use this via FromSystemTime.
2133   int64_t tick =
2134       BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aEventTime);
2135   return TimeStamp::FromSystemTime(tick);
2136 }
2137 
OnReady(jni::Object::Param aQueue)2138 void nsWindow::GeckoViewSupport::OnReady(jni::Object::Param aQueue) {
2139   GeckoSession::Window::LocalRef window(mGeckoViewWindow);
2140   if (!window) {
2141     return;
2142   }
2143   window->OnReady(aQueue);
2144   mIsReady = true;
2145 }
2146 
UserActivity()2147 void nsWindow::UserActivity() {
2148   if (!mIdleService) {
2149     mIdleService = do_GetService("@mozilla.org/widget/idleservice;1");
2150   }
2151 
2152   if (mIdleService) {
2153     mIdleService->ResetIdleTimeOut(0);
2154   }
2155 
2156   if (FindTopLevel() != nsWindow::TopWindow()) {
2157     BringToFront();
2158   }
2159 }
2160 
GetNativeTextEventDispatcherListener()2161 TextEventDispatcherListener* nsWindow::GetNativeTextEventDispatcherListener() {
2162   nsWindow* top = FindTopLevel();
2163   MOZ_ASSERT(top);
2164 
2165   if (!top->mEditableSupport) {
2166     // Non-GeckoView windows don't support IME operations.
2167     return nullptr;
2168   }
2169   return top->mEditableSupport;
2170 }
2171 
SetInputContext(const InputContext & aContext,const InputContextAction & aAction)2172 void nsWindow::SetInputContext(const InputContext& aContext,
2173                                const InputContextAction& aAction) {
2174   nsWindow* top = FindTopLevel();
2175   MOZ_ASSERT(top);
2176 
2177   if (!top->mEditableSupport) {
2178     // Non-GeckoView windows don't support IME operations.
2179     return;
2180   }
2181 
2182   // We are using an IME event later to notify Java, and the IME event
2183   // will be processed by the top window. Therefore, to ensure the
2184   // IME event uses the correct mInputContext, we need to let the top
2185   // window process SetInputContext
2186   top->mEditableSupport->SetInputContext(aContext, aAction);
2187 }
2188 
GetInputContext()2189 InputContext nsWindow::GetInputContext() {
2190   nsWindow* top = FindTopLevel();
2191   MOZ_ASSERT(top);
2192 
2193   if (!top->mEditableSupport) {
2194     // Non-GeckoView windows don't support IME operations.
2195     return InputContext();
2196   }
2197 
2198   // We let the top window process SetInputContext,
2199   // so we should let it process GetInputContext as well.
2200   return top->mEditableSupport->GetInputContext();
2201 }
2202 
SynthesizeNativeTouchPoint(uint32_t aPointerId,TouchPointerState aPointerState,LayoutDeviceIntPoint aPoint,double aPointerPressure,uint32_t aPointerOrientation,nsIObserver * aObserver)2203 nsresult nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId,
2204                                               TouchPointerState aPointerState,
2205                                               LayoutDeviceIntPoint aPoint,
2206                                               double aPointerPressure,
2207                                               uint32_t aPointerOrientation,
2208                                               nsIObserver* aObserver) {
2209   mozilla::widget::AutoObserverNotifier notifier(aObserver, "touchpoint");
2210 
2211   int eventType;
2212   switch (aPointerState) {
2213     case TOUCH_CONTACT:
2214       // This could be a ACTION_DOWN or ACTION_MOVE depending on the
2215       // existing state; it is mapped to the right thing in Java.
2216       eventType = java::sdk::MotionEvent::ACTION_POINTER_DOWN;
2217       break;
2218     case TOUCH_REMOVE:
2219       // This could be turned into a ACTION_UP in Java
2220       eventType = java::sdk::MotionEvent::ACTION_POINTER_UP;
2221       break;
2222     case TOUCH_CANCEL:
2223       eventType = java::sdk::MotionEvent::ACTION_CANCEL;
2224       break;
2225     case TOUCH_HOVER:  // not supported for now
2226     default:
2227       return NS_ERROR_UNEXPECTED;
2228   }
2229 
2230   MOZ_ASSERT(mNPZCSupport);
2231   const auto& npzc = mNPZCSupport->GetJavaNPZC();
2232   const auto& bounds = FindTopLevel()->mBounds;
2233   aPoint.x -= bounds.x;
2234   aPoint.y -= bounds.y;
2235 
2236   DispatchToUiThread(
2237       "nsWindow::SynthesizeNativeTouchPoint",
2238       [npzc = java::PanZoomController::NativeProvider::GlobalRef(npzc),
2239        aPointerId, eventType, aPoint, aPointerPressure, aPointerOrientation] {
2240         npzc->SynthesizeNativeTouchPoint(aPointerId, eventType, aPoint.x,
2241                                          aPoint.y, aPointerPressure,
2242                                          aPointerOrientation);
2243       });
2244   return NS_OK;
2245 }
2246 
SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,uint32_t aNativeMessage,uint32_t aModifierFlags,nsIObserver * aObserver)2247 nsresult nsWindow::SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
2248                                               uint32_t aNativeMessage,
2249                                               uint32_t aModifierFlags,
2250                                               nsIObserver* aObserver) {
2251   mozilla::widget::AutoObserverNotifier notifier(aObserver, "mouseevent");
2252 
2253   MOZ_ASSERT(mNPZCSupport);
2254   const auto& npzc = mNPZCSupport->GetJavaNPZC();
2255   const auto& bounds = FindTopLevel()->mBounds;
2256   aPoint.x -= bounds.x;
2257   aPoint.y -= bounds.y;
2258 
2259   DispatchToUiThread(
2260       "nsWindow::SynthesizeNativeMouseEvent",
2261       [npzc = java::PanZoomController::NativeProvider::GlobalRef(npzc),
2262        aNativeMessage, aPoint] {
2263         npzc->SynthesizeNativeMouseEvent(aNativeMessage, aPoint.x, aPoint.y);
2264       });
2265   return NS_OK;
2266 }
2267 
SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,nsIObserver * aObserver)2268 nsresult nsWindow::SynthesizeNativeMouseMove(LayoutDeviceIntPoint aPoint,
2269                                              nsIObserver* aObserver) {
2270   mozilla::widget::AutoObserverNotifier notifier(aObserver, "mouseevent");
2271 
2272   MOZ_ASSERT(mNPZCSupport);
2273   const auto& npzc = mNPZCSupport->GetJavaNPZC();
2274   const auto& bounds = FindTopLevel()->mBounds;
2275   aPoint.x -= bounds.x;
2276   aPoint.y -= bounds.y;
2277 
2278   DispatchToUiThread(
2279       "nsWindow::SynthesizeNativeMouseMove",
2280       [npzc = java::PanZoomController::NativeProvider::GlobalRef(npzc),
2281        aPoint] {
2282         npzc->SynthesizeNativeMouseEvent(
2283             java::sdk::MotionEvent::ACTION_HOVER_MOVE, aPoint.x, aPoint.y);
2284       });
2285   return NS_OK;
2286 }
2287 
WidgetPaintsBackground()2288 bool nsWindow::WidgetPaintsBackground() {
2289   return StaticPrefs::android_widget_paints_background();
2290 }
2291 
NeedsPaint()2292 bool nsWindow::NeedsPaint() {
2293   if (!mLayerViewSupport || mLayerViewSupport->CompositorPaused() ||
2294       // FindTopLevel() != nsWindow::TopWindow() ||
2295       !GetLayerManager(nullptr)) {
2296     return false;
2297   }
2298   return nsIWidget::NeedsPaint();
2299 }
2300 
ConfigureAPZControllerThread()2301 void nsWindow::ConfigureAPZControllerThread() {
2302   nsCOMPtr<nsISerialEventTarget> thread = mozilla::GetAndroidUiThread();
2303   APZThreadUtils::SetControllerThread(thread);
2304 }
2305 
2306 already_AddRefed<GeckoContentController>
CreateRootContentController()2307 nsWindow::CreateRootContentController() {
2308   RefPtr<GeckoContentController> controller =
2309       new AndroidContentController(this, mAPZEventState, mAPZC);
2310   return controller.forget();
2311 }
2312 
GetMaxTouchPoints() const2313 uint32_t nsWindow::GetMaxTouchPoints() const {
2314   return java::GeckoAppShell::GetMaxTouchPoints();
2315 }
2316 
UpdateZoomConstraints(const uint32_t & aPresShellId,const ScrollableLayerGuid::ViewID & aViewId,const mozilla::Maybe<ZoomConstraints> & aConstraints)2317 void nsWindow::UpdateZoomConstraints(
2318     const uint32_t& aPresShellId, const ScrollableLayerGuid::ViewID& aViewId,
2319     const mozilla::Maybe<ZoomConstraints>& aConstraints) {
2320   nsBaseWidget::UpdateZoomConstraints(aPresShellId, aViewId, aConstraints);
2321 }
2322 
GetCompositorBridgeChild() const2323 CompositorBridgeChild* nsWindow::GetCompositorBridgeChild() const {
2324   return mCompositorSession ? mCompositorSession->GetCompositorBridgeChild()
2325                             : nullptr;
2326 }
2327 
GetWidgetScreen()2328 already_AddRefed<nsIScreen> nsWindow::GetWidgetScreen() {
2329   RefPtr<nsIScreen> screen =
2330       ScreenHelperAndroid::GetSingleton()->ScreenForId(mScreenId);
2331   return screen.forget();
2332 }
2333 
SetContentDocumentDisplayed(bool aDisplayed)2334 void nsWindow::SetContentDocumentDisplayed(bool aDisplayed) {
2335   mContentDocumentDisplayed = aDisplayed;
2336 }
2337 
IsContentDocumentDisplayed()2338 bool nsWindow::IsContentDocumentDisplayed() {
2339   return mContentDocumentDisplayed;
2340 }
2341 
RecvToolbarAnimatorMessageFromCompositor(int32_t aMessage)2342 void nsWindow::RecvToolbarAnimatorMessageFromCompositor(int32_t aMessage) {
2343   MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
2344   if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
2345     lvs->RecvToolbarAnimatorMessage(aMessage);
2346   }
2347 }
2348 
UpdateRootFrameMetrics(const ScreenPoint & aScrollOffset,const CSSToScreenScale & aZoom)2349 void nsWindow::UpdateRootFrameMetrics(const ScreenPoint& aScrollOffset,
2350                                       const CSSToScreenScale& aZoom) {
2351   MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
2352   if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
2353     const auto& compositor = lvs->GetJavaCompositor();
2354     mContentDocumentDisplayed = true;
2355     compositor->UpdateRootFrameMetrics(aScrollOffset.x, aScrollOffset.y,
2356                                        aZoom.scale);
2357   }
2358 }
2359 
RecvScreenPixels(Shmem && aMem,const ScreenIntSize & aSize)2360 void nsWindow::RecvScreenPixels(Shmem&& aMem, const ScreenIntSize& aSize) {
2361   MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
2362   if (NativePtr<LayerViewSupport>::Locked lvs{mLayerViewSupport}) {
2363     lvs->RecvScreenPixels(std::move(aMem), aSize);
2364   }
2365 }
2366 
UpdateDynamicToolbarMaxHeight(ScreenIntCoord aHeight)2367 void nsWindow::UpdateDynamicToolbarMaxHeight(ScreenIntCoord aHeight) {
2368   if (mDynamicToolbarMaxHeight == aHeight) {
2369     return;
2370   }
2371 
2372   mDynamicToolbarMaxHeight = aHeight;
2373 
2374   if (mWidgetListener) {
2375     mWidgetListener->DynamicToolbarMaxHeightChanged(aHeight);
2376   }
2377 
2378   if (mAttachedWidgetListener) {
2379     mAttachedWidgetListener->DynamicToolbarMaxHeightChanged(aHeight);
2380   }
2381 }
2382 
UpdateDynamicToolbarOffset(ScreenIntCoord aOffset)2383 void nsWindow::UpdateDynamicToolbarOffset(ScreenIntCoord aOffset) {
2384   if (mWidgetListener) {
2385     mWidgetListener->DynamicToolbarOffsetChanged(aOffset);
2386   }
2387 
2388   if (mAttachedWidgetListener) {
2389     mAttachedWidgetListener->DynamicToolbarOffsetChanged(aOffset);
2390   }
2391 }
2392 
GetSafeAreaInsets() const2393 ScreenIntMargin nsWindow::GetSafeAreaInsets() const { return mSafeAreaInsets; }
2394 
UpdateSafeAreaInsets(const ScreenIntMargin & aSafeAreaInsets)2395 void nsWindow::UpdateSafeAreaInsets(const ScreenIntMargin& aSafeAreaInsets) {
2396   mSafeAreaInsets = aSafeAreaInsets;
2397 
2398   if (mWidgetListener) {
2399     mWidgetListener->SafeAreaInsetsChanged(aSafeAreaInsets);
2400   }
2401 
2402   if (mAttachedWidgetListener) {
2403     mAttachedWidgetListener->SafeAreaInsetsChanged(aSafeAreaInsets);
2404   }
2405 }
2406 
OnLoadRequest(mozilla::jni::String::Param aUri,int32_t aWindowType,int32_t aFlags,mozilla::jni::String::Param aTriggeringUri,bool aHasUserGesture,bool aIsTopLevel) const2407 auto nsWindow::GeckoViewSupport::OnLoadRequest(
2408     mozilla::jni::String::Param aUri, int32_t aWindowType, int32_t aFlags,
2409     mozilla::jni::String::Param aTriggeringUri, bool aHasUserGesture,
2410     bool aIsTopLevel) const -> java::GeckoResult::LocalRef {
2411   GeckoSession::Window::LocalRef window(mGeckoViewWindow);
2412   if (!window) {
2413     return nullptr;
2414   }
2415   return window->OnLoadRequest(aUri, aWindowType, aFlags, aTriggeringUri,
2416                                aHasUserGesture, aIsTopLevel);
2417 }
CreateTopLevelWindow()2418 already_AddRefed<nsIWidget> nsIWidget::CreateTopLevelWindow() {
2419   nsCOMPtr<nsIWidget> window = new nsWindow();
2420   return window.forget();
2421 }
2422 
CreateChildWindow()2423 already_AddRefed<nsIWidget> nsIWidget::CreateChildWindow() {
2424   nsCOMPtr<nsIWidget> window = new nsWindow();
2425   return window.forget();
2426 }
2427