Bug 1843230 - Remove IsWin8OrLater checks from dom/geolocation/ r=emk
[gecko.git] / dom / ipc / BrowserParent.cpp
blobd0bf99c8a6e34a1752b30b8f7a7fd3dc13f46bde
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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/. */
7 #include "base/basictypes.h"
9 #include "BrowserParent.h"
10 #include "mozilla/AlreadyAddRefed.h"
11 #include "mozilla/EventForwards.h"
13 #ifdef ACCESSIBILITY
14 # include "mozilla/a11y/DocAccessibleParent.h"
15 # include "mozilla/a11y/Platform.h"
16 # include "nsAccessibilityService.h"
17 #endif
18 #include "mozilla/Components.h"
19 #include "mozilla/dom/BrowserHost.h"
20 #include "mozilla/dom/BrowserSessionStore.h"
21 #include "mozilla/dom/BrowsingContextGroup.h"
22 #include "mozilla/dom/CancelContentJSOptionsBinding.h"
23 #include "mozilla/dom/ChromeMessageSender.h"
24 #include "mozilla/dom/ContentParent.h"
25 #include "mozilla/dom/ContentProcessManager.h"
26 #include "mozilla/dom/DataTransfer.h"
27 #include "mozilla/dom/DataTransferItemList.h"
28 #include "mozilla/dom/DocumentInlines.h"
29 #include "mozilla/dom/Event.h"
30 #include "mozilla/dom/indexedDB/ActorsParent.h"
31 #include "mozilla/dom/PaymentRequestParent.h"
32 #include "mozilla/dom/PointerEventHandler.h"
33 #include "mozilla/dom/BrowserBridgeParent.h"
34 #include "mozilla/dom/RemoteDragStartData.h"
35 #include "mozilla/dom/RemoteWebProgressRequest.h"
36 #include "mozilla/dom/SessionHistoryEntry.h"
37 #include "mozilla/dom/SessionStoreParent.h"
38 #include "mozilla/dom/UserActivation.h"
39 #include "mozilla/EventStateManager.h"
40 #include "mozilla/gfx/2D.h"
41 #include "mozilla/gfx/DataSurfaceHelpers.h"
42 #include "mozilla/gfx/GPUProcessManager.h"
43 #include "mozilla/IMEStateManager.h"
44 #include "mozilla/ipc/Endpoint.h"
45 #include "mozilla/layers/AsyncDragMetrics.h"
46 #include "mozilla/layers/InputAPZContext.h"
47 #include "mozilla/layout/RemoteLayerTreeOwner.h"
48 #include "mozilla/LookAndFeel.h"
49 #include "mozilla/Maybe.h"
50 #include "mozilla/MiscEvents.h"
51 #include "mozilla/MouseEvents.h"
52 #include "mozilla/NativeKeyBindingsType.h"
53 #include "mozilla/net/NeckoChild.h"
54 #include "mozilla/net/CookieJarSettings.h"
55 #include "mozilla/Preferences.h"
56 #include "mozilla/PresShell.h"
57 #include "mozilla/ProcessHangMonitor.h"
58 #include "mozilla/RecursiveMutex.h"
59 #include "mozilla/RefPtr.h"
60 #include "mozilla/StaticPrefs_dom.h"
61 #include "mozilla/TextEventDispatcher.h"
62 #include "mozilla/TextEvents.h"
63 #include "mozilla/TouchEvents.h"
64 #include "mozilla/UniquePtr.h"
65 #include "mozilla/Unused.h"
66 #include "nsCOMPtr.h"
67 #include "nsContentUtils.h"
68 #include "nsDebug.h"
69 #include "nsFocusManager.h"
70 #include "nsFrameLoader.h"
71 #include "nsFrameLoaderOwner.h"
72 #include "nsFrameManager.h"
73 #include "nsIBaseWindow.h"
74 #include "nsIBrowser.h"
75 #include "nsIBrowserController.h"
76 #include "nsIContent.h"
77 #include "nsICookieJarSettings.h"
78 #include "nsIDocShell.h"
79 #include "nsIDocShellTreeOwner.h"
80 #include "nsImportModule.h"
81 #include "nsIInterfaceRequestorUtils.h"
82 #include "nsILoadInfo.h"
83 #include "nsIPromptFactory.h"
84 #include "nsIURI.h"
85 #include "nsIWebBrowserChrome.h"
86 #include "nsIWebProtocolHandlerRegistrar.h"
87 #include "nsIWindowWatcher.h"
88 #include "nsIXPConnect.h"
89 #include "nsIXULBrowserWindow.h"
90 #include "nsIAppWindow.h"
91 #include "nsLayoutUtils.h"
92 #include "nsQueryActor.h"
93 #include "nsSHistory.h"
94 #include "nsViewManager.h"
95 #include "nsVariant.h"
96 #include "nsIWidget.h"
97 #include "nsNetUtil.h"
98 #ifndef XP_WIN
99 # include "nsJARProtocolHandler.h"
100 #endif
101 #include "nsPIDOMWindow.h"
102 #include "nsPrintfCString.h"
103 #include "nsQueryObject.h"
104 #include "nsServiceManagerUtils.h"
105 #include "nsThreadUtils.h"
106 #include "PermissionMessageUtils.h"
107 #include "StructuredCloneData.h"
108 #include "ColorPickerParent.h"
109 #include "FilePickerParent.h"
110 #include "BrowserChild.h"
111 #include "nsNetCID.h"
112 #include "nsIAuthInformation.h"
113 #include "nsIAuthPromptCallback.h"
114 #include "nsAuthInformationHolder.h"
115 #include "nsICancelable.h"
116 #include "gfxUtils.h"
117 #include "nsILoginManagerAuthPrompter.h"
118 #include "nsPIWindowRoot.h"
119 #include "nsReadableUtils.h"
120 #include "nsIAuthPrompt2.h"
121 #include "gfxDrawable.h"
122 #include "ImageOps.h"
123 #include "UnitTransforms.h"
124 #include <algorithm>
125 #include "mozilla/NullPrincipal.h"
126 #include "mozilla/WebBrowserPersistDocumentParent.h"
127 #include "ProcessPriorityManager.h"
128 #include "nsString.h"
129 #include "IHistory.h"
130 #include "mozilla/dom/WindowGlobalParent.h"
131 #include "mozilla/dom/CanonicalBrowsingContext.h"
132 #include "mozilla/ProfilerLabels.h"
133 #include "MMPrinter.h"
134 #include "mozilla/dom/CrashReport.h"
135 #include "nsISecureBrowserUI.h"
136 #include "nsIXULRuntime.h"
137 #include "VsyncSource.h"
138 #include "nsSubDocumentFrame.h"
140 #ifdef XP_WIN
141 # include "FxRWindowManager.h"
142 #endif
144 #if defined(XP_WIN) && defined(ACCESSIBILITY)
145 # include "mozilla/a11y/AccessibleWrap.h"
146 # include "mozilla/a11y/Compatibility.h"
147 # include "mozilla/a11y/nsWinUtils.h"
148 #endif
150 #ifdef MOZ_ANDROID_HISTORY
151 # include "GeckoViewHistory.h"
152 #endif
154 #if defined(MOZ_WIDGET_ANDROID)
155 # include "mozilla/widget/nsWindow.h"
156 #endif // defined(MOZ_WIDGET_ANDROID)
158 using namespace mozilla::dom;
159 using namespace mozilla::ipc;
160 using namespace mozilla::layers;
161 using namespace mozilla::layout;
162 using namespace mozilla::services;
163 using namespace mozilla::widget;
164 using namespace mozilla::gfx;
166 using mozilla::LazyLogModule;
168 extern mozilla::LazyLogModule gSHIPBFCacheLog;
170 LazyLogModule gBrowserFocusLog("BrowserFocus");
172 #define LOGBROWSERFOCUS(args) \
173 MOZ_LOG(gBrowserFocusLog, mozilla::LogLevel::Debug, args)
175 /* static */
176 BrowserParent* BrowserParent::sFocus = nullptr;
177 /* static */
178 BrowserParent* BrowserParent::sTopLevelWebFocus = nullptr;
179 /* static */
180 BrowserParent* BrowserParent::sLastMouseRemoteTarget = nullptr;
182 // The flags passed by the webProgress notifications are 16 bits shifted
183 // from the ones registered by webProgressListeners.
184 #define NOTIFY_FLAG_SHIFT 16
186 namespace mozilla {
189 * Store data of a keypress event which is requesting to handled it in a remote
190 * process or some remote processes.
192 class RequestingAccessKeyEventData {
193 public:
194 RequestingAccessKeyEventData() = delete;
196 static void OnBrowserParentCreated() {
197 MOZ_ASSERT(sBrowserParentCount <= INT32_MAX);
198 sBrowserParentCount++;
200 static void OnBrowserParentDestroyed() {
201 MOZ_ASSERT(sBrowserParentCount > 0);
202 sBrowserParentCount--;
203 // To avoid memory leak, we need to reset sData when the last BrowserParent
204 // is destroyed.
205 if (!sBrowserParentCount) {
206 Clear();
210 static void Set(const WidgetKeyboardEvent& aKeyPressEvent) {
211 MOZ_ASSERT(aKeyPressEvent.mMessage == eKeyPress);
212 MOZ_ASSERT(sBrowserParentCount > 0);
213 sData =
214 Some(Data{aKeyPressEvent.mAlternativeCharCodes, aKeyPressEvent.mKeyCode,
215 aKeyPressEvent.mCharCode, aKeyPressEvent.mKeyNameIndex,
216 aKeyPressEvent.mCodeNameIndex, aKeyPressEvent.mKeyValue,
217 aKeyPressEvent.mModifiers});
220 static void Clear() { sData.reset(); }
222 [[nodiscard]] static bool Equals(const WidgetKeyboardEvent& aKeyPressEvent) {
223 MOZ_ASSERT(sBrowserParentCount > 0);
224 return sData.isSome() && sData->Equals(aKeyPressEvent);
227 [[nodiscard]] static bool IsSet() {
228 MOZ_ASSERT(sBrowserParentCount > 0);
229 return sData.isSome();
232 private:
233 struct Data {
234 [[nodiscard]] bool Equals(const WidgetKeyboardEvent& aKeyPressEvent) {
235 return mKeyCode == aKeyPressEvent.mKeyCode &&
236 mCharCode == aKeyPressEvent.mCharCode &&
237 mKeyNameIndex == aKeyPressEvent.mKeyNameIndex &&
238 mCodeNameIndex == aKeyPressEvent.mCodeNameIndex &&
239 mKeyValue == aKeyPressEvent.mKeyValue &&
240 mModifiers == aKeyPressEvent.mModifiers &&
241 mAlternativeCharCodes == aKeyPressEvent.mAlternativeCharCodes;
244 CopyableTArray<AlternativeCharCode> mAlternativeCharCodes;
245 uint32_t mKeyCode;
246 uint32_t mCharCode;
247 KeyNameIndex mKeyNameIndex;
248 CodeNameIndex mCodeNameIndex;
249 nsString mKeyValue;
250 Modifiers mModifiers;
252 static Maybe<Data> sData;
253 static int32_t sBrowserParentCount;
255 int32_t RequestingAccessKeyEventData::sBrowserParentCount = 0;
256 Maybe<RequestingAccessKeyEventData::Data> RequestingAccessKeyEventData::sData;
258 namespace dom {
260 BrowserParent::LayerToBrowserParentTable*
261 BrowserParent::sLayerToBrowserParentTable = nullptr;
263 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserParent)
264 NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
265 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
266 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener)
267 NS_INTERFACE_MAP_END
268 NS_IMPL_CYCLE_COLLECTION_WEAK(BrowserParent, mFrameLoader, mBrowsingContext)
269 NS_IMPL_CYCLE_COLLECTING_ADDREF(BrowserParent)
270 NS_IMPL_CYCLE_COLLECTING_RELEASE(BrowserParent)
272 BrowserParent::BrowserParent(ContentParent* aManager, const TabId& aTabId,
273 const TabContext& aContext,
274 CanonicalBrowsingContext* aBrowsingContext,
275 uint32_t aChromeFlags)
276 : TabContext(aContext),
277 mTabId(aTabId),
278 mManager(aManager),
279 mBrowsingContext(aBrowsingContext),
280 mFrameElement(nullptr),
281 mBrowserDOMWindow(nullptr),
282 mFrameLoader(nullptr),
283 mChromeFlags(aChromeFlags),
284 mBrowserBridgeParent(nullptr),
285 mBrowserHost(nullptr),
286 mContentCache(*this),
287 mRemoteLayerTreeOwner{},
288 mLayerTreeEpoch{1},
289 mChildToParentConversionMatrix{},
290 mRect(0, 0, 0, 0),
291 mDimensions(0, 0),
292 mDPI(0),
293 mRounding(0),
294 mDefaultScale(0),
295 mUpdatedDimensions(false),
296 mSizeMode(nsSizeMode_Normal),
297 mClientOffset{},
298 mChromeOffset{},
299 mCreatingWindow(false),
300 mDelayedFrameScripts{},
301 mVsyncParent(nullptr),
302 mMarkedDestroying(false),
303 mIsDestroyed(false),
304 mRemoteTargetSetsCursor(false),
305 mIsPreservingLayers(false),
306 mRenderLayers(true),
307 mPriorityHint(false),
308 mHasLayers(false),
309 mHasPresented(false),
310 mIsReadyToHandleInputEvents(false),
311 mIsMouseEnterIntoWidgetEventSuppressed(false),
312 mLockedNativePointer(false),
313 mShowingTooltip(false) {
314 MOZ_ASSERT(aManager);
316 RequestingAccessKeyEventData::OnBrowserParentCreated();
318 // When the input event queue is disabled, we don't need to handle the case
319 // that some input events are dispatched before PBrowserConstructor.
320 mIsReadyToHandleInputEvents = !ContentParent::IsInputEventQueueSupported();
322 // Make sure to compute our process priority if needed before the block of
323 // code below. This makes sure the block below prioritizes our process if
324 // needed.
325 if (aBrowsingContext->IsTop()) {
326 RecomputeProcessPriority();
329 // If we're in a BC tree that is active with respect to the priority manager,
330 // ensure that this new BrowserParent is marked as active. This ensures that
331 // the process will be prioritized in a cross-site iframe navigation in an
332 // active tab, and also that the process is correctly prioritized if we got
333 // created for a browsing context which was already active.
334 if (aBrowsingContext->Top()->IsPriorityActive()) {
335 ProcessPriorityManager::BrowserPriorityChanged(this, true);
339 BrowserParent::~BrowserParent() {
340 RequestingAccessKeyEventData::OnBrowserParentDestroyed();
343 /* static */
344 BrowserParent* BrowserParent::GetFocused() { return sFocus; }
346 /* static */
347 BrowserParent* BrowserParent::GetLastMouseRemoteTarget() {
348 return sLastMouseRemoteTarget;
351 /*static*/
352 BrowserParent* BrowserParent::GetFrom(nsFrameLoader* aFrameLoader) {
353 if (!aFrameLoader) {
354 return nullptr;
356 return aFrameLoader->GetBrowserParent();
359 /*static*/
360 BrowserParent* BrowserParent::GetFrom(PBrowserParent* aBrowserParent) {
361 return static_cast<BrowserParent*>(aBrowserParent);
364 /*static*/
365 BrowserParent* BrowserParent::GetFrom(nsIContent* aContent) {
366 RefPtr<nsFrameLoaderOwner> loaderOwner = do_QueryObject(aContent);
367 if (!loaderOwner) {
368 return nullptr;
370 RefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
371 return GetFrom(frameLoader);
374 /* static */
375 BrowserParent* BrowserParent::GetBrowserParentFromLayersId(
376 layers::LayersId aLayersId) {
377 if (!sLayerToBrowserParentTable) {
378 return nullptr;
380 return sLayerToBrowserParentTable->Get(uint64_t(aLayersId));
383 /*static*/
384 TabId BrowserParent::GetTabIdFrom(nsIDocShell* docShell) {
385 nsCOMPtr<nsIBrowserChild> browserChild(BrowserChild::GetFrom(docShell));
386 if (browserChild) {
387 return static_cast<BrowserChild*>(browserChild.get())->GetTabId();
389 return TabId(0);
392 void BrowserParent::AddBrowserParentToTable(layers::LayersId aLayersId,
393 BrowserParent* aBrowserParent) {
394 if (!sLayerToBrowserParentTable) {
395 sLayerToBrowserParentTable = new LayerToBrowserParentTable();
397 sLayerToBrowserParentTable->InsertOrUpdate(uint64_t(aLayersId),
398 aBrowserParent);
401 void BrowserParent::RemoveBrowserParentFromTable(layers::LayersId aLayersId) {
402 if (!sLayerToBrowserParentTable) {
403 return;
405 sLayerToBrowserParentTable->Remove(uint64_t(aLayersId));
406 if (sLayerToBrowserParentTable->Count() == 0) {
407 delete sLayerToBrowserParentTable;
408 sLayerToBrowserParentTable = nullptr;
412 already_AddRefed<nsILoadContext> BrowserParent::GetLoadContext() {
413 return do_AddRef(mBrowsingContext);
417 * Will return nullptr if there is no outer window available for the
418 * document hosting the owner element of this BrowserParent. Also will return
419 * nullptr if that outer window is in the process of closing.
421 already_AddRefed<nsPIDOMWindowOuter> BrowserParent::GetParentWindowOuter() {
422 nsCOMPtr<nsIContent> frame = GetOwnerElement();
423 if (!frame) {
424 return nullptr;
427 nsCOMPtr<nsPIDOMWindowOuter> parent = frame->OwnerDoc()->GetWindow();
428 if (!parent || parent->Closed()) {
429 return nullptr;
432 return parent.forget();
435 already_AddRefed<nsIWidget> BrowserParent::GetTopLevelWidget() {
436 if (RefPtr<Element> element = mFrameElement) {
437 if (PresShell* presShell = element->OwnerDoc()->GetPresShell()) {
438 return do_AddRef(presShell->GetViewManager()->GetRootWidget());
441 return nullptr;
444 already_AddRefed<nsIWidget> BrowserParent::GetTextInputHandlingWidget() const {
445 if (!mFrameElement) {
446 return nullptr;
448 PresShell* presShell = mFrameElement->OwnerDoc()->GetPresShell();
449 if (!presShell) {
450 return nullptr;
452 nsPresContext* presContext = presShell->GetPresContext();
453 if (!presContext) {
454 return nullptr;
456 nsCOMPtr<nsIWidget> widget = presContext->GetTextInputHandlingWidget();
457 return widget.forget();
460 already_AddRefed<nsIWidget> BrowserParent::GetWidget() const {
461 if (!mFrameElement) {
462 return nullptr;
464 nsCOMPtr<nsIWidget> widget = nsContentUtils::WidgetForContent(mFrameElement);
465 if (!widget) {
466 widget = nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc());
468 return widget.forget();
471 already_AddRefed<nsIWidget> BrowserParent::GetDocWidget() const {
472 if (!mFrameElement) {
473 return nullptr;
475 return do_AddRef(
476 nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc()));
479 nsIXULBrowserWindow* BrowserParent::GetXULBrowserWindow() {
480 if (!mFrameElement) {
481 return nullptr;
484 nsCOMPtr<nsIDocShell> docShell = mFrameElement->OwnerDoc()->GetDocShell();
485 if (!docShell) {
486 return nullptr;
489 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
490 docShell->GetTreeOwner(getter_AddRefs(treeOwner));
491 if (!treeOwner) {
492 return nullptr;
495 nsCOMPtr<nsIAppWindow> window = do_GetInterface(treeOwner);
496 if (!window) {
497 return nullptr;
500 nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow;
501 window->GetXULBrowserWindow(getter_AddRefs(xulBrowserWindow));
502 return xulBrowserWindow;
505 uint32_t BrowserParent::GetMaxTouchPoints(Element* aElement) {
506 if (!aElement) {
507 return 0;
510 if (StaticPrefs::dom_maxtouchpoints_testing_value() >= 0) {
511 return StaticPrefs::dom_maxtouchpoints_testing_value();
514 nsIWidget* widget = nsContentUtils::WidgetForDocument(aElement->OwnerDoc());
515 return widget ? widget->GetMaxTouchPoints() : 0;
518 a11y::DocAccessibleParent* BrowserParent::GetTopLevelDocAccessible() const {
519 #ifdef ACCESSIBILITY
520 // XXX Consider managing non top level PDocAccessibles with their parent
521 // document accessible.
522 const ManagedContainer<PDocAccessibleParent>& docs =
523 ManagedPDocAccessibleParent();
524 for (auto* key : docs) {
525 auto* doc = static_cast<a11y::DocAccessibleParent*>(key);
526 // We want the document for this BrowserParent even if it's for an
527 // embedded out-of-process iframe. Therefore, we use
528 // IsTopLevelInContentProcess. In contrast, using IsToplevel would only
529 // include documents that aren't embedded; e.g. tab documents.
530 if (doc->IsTopLevelInContentProcess() && !doc->IsShutdown()) {
531 return doc;
534 #endif
535 return nullptr;
538 LayersId BrowserParent::GetLayersId() const {
539 if (!mRemoteLayerTreeOwner.IsInitialized()) {
540 return LayersId{};
542 return mRemoteLayerTreeOwner.GetLayersId();
545 BrowserBridgeParent* BrowserParent::GetBrowserBridgeParent() const {
546 return mBrowserBridgeParent;
549 BrowserHost* BrowserParent::GetBrowserHost() const { return mBrowserHost; }
551 ParentShowInfo BrowserParent::GetShowInfo() {
552 TryCacheDPIAndScale();
553 if (mFrameElement) {
554 nsAutoString name;
555 mFrameElement->GetAttr(nsGkAtoms::name, name);
556 bool isTransparent =
557 nsContentUtils::IsChromeDoc(mFrameElement->OwnerDoc()) &&
558 mFrameElement->HasAttr(nsGkAtoms::transparent);
559 return ParentShowInfo(name, false, isTransparent, mDPI, mRounding,
560 mDefaultScale.scale);
563 return ParentShowInfo(u""_ns, false, false, mDPI, mRounding,
564 mDefaultScale.scale);
567 already_AddRefed<nsIPrincipal> BrowserParent::GetContentPrincipal() const {
568 nsCOMPtr<nsIBrowser> browser =
569 mFrameElement ? mFrameElement->AsBrowser() : nullptr;
570 NS_ENSURE_TRUE(browser, nullptr);
572 RefPtr<nsIPrincipal> principal;
574 nsresult rv;
575 rv = browser->GetContentPrincipal(getter_AddRefs(principal));
576 NS_ENSURE_SUCCESS(rv, nullptr);
578 return principal.forget();
581 void BrowserParent::SetOwnerElement(Element* aElement) {
582 // If we held previous content then unregister for its events.
583 RemoveWindowListeners();
585 // If we change top-level documents then we need to change our
586 // registration with them.
587 RefPtr<nsPIWindowRoot> curTopLevelWin, newTopLevelWin;
588 if (mFrameElement) {
589 curTopLevelWin = nsContentUtils::GetWindowRoot(mFrameElement->OwnerDoc());
591 if (aElement) {
592 newTopLevelWin = nsContentUtils::GetWindowRoot(aElement->OwnerDoc());
594 bool isSameTopLevelWin = curTopLevelWin == newTopLevelWin;
595 if (mBrowserHost && curTopLevelWin && !isSameTopLevelWin) {
596 curTopLevelWin->RemoveBrowser(mBrowserHost);
599 // Update to the new content, and register to listen for events from it.
600 mFrameElement = aElement;
602 if (mBrowserHost && newTopLevelWin && !isSameTopLevelWin) {
603 newTopLevelWin->AddBrowser(mBrowserHost);
606 #if defined(XP_WIN) && defined(ACCESSIBILITY)
607 if (!mIsDestroyed) {
608 uintptr_t newWindowHandle = 0;
609 if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
610 newWindowHandle =
611 reinterpret_cast<uintptr_t>(widget->GetNativeData(NS_NATIVE_WINDOW));
613 Unused << SendUpdateNativeWindowHandle(newWindowHandle);
614 a11y::DocAccessibleParent* doc = GetTopLevelDocAccessible();
615 if (doc) {
616 HWND hWnd = reinterpret_cast<HWND>(doc->GetEmulatedWindowHandle());
617 if (hWnd) {
618 HWND parentHwnd = reinterpret_cast<HWND>(newWindowHandle);
619 if (parentHwnd != ::GetParent(hWnd)) {
620 ::SetParent(hWnd, parentHwnd);
625 #endif
627 AddWindowListeners();
629 // The DPI depends on our frame element's widget, so invalidate now in case
630 // we've tried to cache it already.
631 mDPI = -1;
632 TryCacheDPIAndScale();
634 if (mRemoteLayerTreeOwner.IsInitialized()) {
635 mRemoteLayerTreeOwner.OwnerContentChanged();
638 // Set our BrowsingContext's embedder if we're not embedded within a
639 // BrowserBridgeParent.
640 if (!GetBrowserBridgeParent() && mBrowsingContext && mFrameElement) {
641 mBrowsingContext->SetEmbedderElement(mFrameElement);
644 UpdateVsyncParentVsyncDispatcher();
646 VisitChildren([aElement](BrowserBridgeParent* aBrowser) {
647 if (auto* browserParent = aBrowser->GetBrowserParent()) {
648 browserParent->SetOwnerElement(aElement);
653 void BrowserParent::CacheFrameLoader(nsFrameLoader* aFrameLoader) {
654 mFrameLoader = aFrameLoader;
657 void BrowserParent::AddWindowListeners() {
658 if (mFrameElement) {
659 if (nsCOMPtr<nsPIDOMWindowOuter> window =
660 mFrameElement->OwnerDoc()->GetWindow()) {
661 nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
662 if (eventTarget) {
663 eventTarget->AddEventListener(u"MozUpdateWindowPos"_ns, this, false,
664 false);
665 eventTarget->AddEventListener(u"fullscreenchange"_ns, this, false,
666 false);
672 void BrowserParent::RemoveWindowListeners() {
673 if (mFrameElement && mFrameElement->OwnerDoc()->GetWindow()) {
674 nsCOMPtr<nsPIDOMWindowOuter> window =
675 mFrameElement->OwnerDoc()->GetWindow();
676 nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
677 if (eventTarget) {
678 eventTarget->RemoveEventListener(u"MozUpdateWindowPos"_ns, this, false);
679 eventTarget->RemoveEventListener(u"fullscreenchange"_ns, this, false);
684 void BrowserParent::Deactivated() {
685 if (mShowingTooltip) {
686 // Reuse the normal tooltip hiding method.
687 mozilla::Unused << RecvHideTooltip();
689 UnlockNativePointer();
690 UnsetTopLevelWebFocus(this);
691 UnsetLastMouseRemoteTarget(this);
692 PointerLockManager::ReleaseLockedRemoteTarget(this);
693 PointerEventHandler::ReleasePointerCaptureRemoteTarget(this);
694 PresShell::ReleaseCapturingRemoteTarget(this);
695 ProcessPriorityManager::BrowserPriorityChanged(this, /* aPriority = */ false);
698 void BrowserParent::Destroy() {
699 // Aggressively release the window to avoid leaking the world in shutdown
700 // corner cases.
701 mBrowserDOMWindow = nullptr;
703 if (mIsDestroyed) {
704 return;
707 Deactivated();
709 RemoveWindowListeners();
711 #ifdef ACCESSIBILITY
712 if (a11y::DocAccessibleParent* tabDoc = GetTopLevelDocAccessible()) {
713 # if defined(ANDROID)
714 MonitorAutoLock mal(nsAccessibilityService::GetAndroidMonitor());
715 # endif
716 tabDoc->Destroy();
718 #endif
721 // The following sequence assumes that the keepalive state does not change
722 // between the calls, but our ThreadsafeHandle might be accessed from other
723 // threads in the meantime.
724 RecursiveMutexAutoLock lock(Manager()->ThreadsafeHandleMutex());
726 // If we are shutting down everything or we know to be the last
727 // BrowserParent, signal the impending shutdown early to the content process
728 // to avoid to run the SendDestroy before we know we are ExpectingShutdown.
729 Manager()->NotifyTabWillDestroy();
731 // If this fails, it's most likely due to a content-process crash, and
732 // auto-cleanup will kick in. Otherwise, the child side will destroy itself
733 // and send back __delete__().
734 (void)SendDestroy();
735 mIsDestroyed = true;
737 Manager()->NotifyTabDestroying();
740 // This `AddKeepAlive` will be cleared if `mMarkedDestroying` is set in
741 // `ActorDestroy`. Out of caution, we don't add the `KeepAlive` if our IPC
742 // actor has somehow already been destroyed, as that would mean `ActorDestroy`
743 // won't be called.
744 if (CanRecv()) {
745 mBrowsingContext->Group()->AddKeepAlive();
748 mMarkedDestroying = true;
751 mozilla::ipc::IPCResult BrowserParent::RecvDidUnsuppressPainting() {
752 if (!mFrameElement) {
753 return IPC_OK();
755 nsSubDocumentFrame* subdocFrame =
756 do_QueryFrame(mFrameElement->GetPrimaryFrame());
757 if (subdocFrame && subdocFrame->HasRetainedPaintData()) {
758 subdocFrame->ClearRetainedPaintData();
760 return IPC_OK();
763 mozilla::ipc::IPCResult BrowserParent::RecvEnsureLayersConnected(
764 CompositorOptions* aCompositorOptions) {
765 if (mRemoteLayerTreeOwner.IsInitialized()) {
766 mRemoteLayerTreeOwner.EnsureLayersConnected(aCompositorOptions);
768 return IPC_OK();
771 void BrowserParent::ActorDestroy(ActorDestroyReason why) {
772 Manager()->NotifyTabDestroyed(mTabId, mMarkedDestroying);
774 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
775 if (cpm) {
776 cpm->UnregisterRemoteFrame(mTabId);
779 if (mRemoteLayerTreeOwner.IsInitialized()) {
780 auto layersId = mRemoteLayerTreeOwner.GetLayersId();
781 if (mFrameElement) {
782 nsSubDocumentFrame* f = do_QueryFrame(mFrameElement->GetPrimaryFrame());
783 if (f && f->HasRetainedPaintData() &&
784 f->GetRemotePaintData().mLayersId == layersId) {
785 f->ClearRetainedPaintData();
789 // It's important to unmap layers after the remote browser has been
790 // destroyed, otherwise it may still send messages to the compositor which
791 // will reject them, causing assertions.
792 RemoveBrowserParentFromTable(layersId);
793 mRemoteLayerTreeOwner.Destroy();
796 // Even though BrowserParent::Destroy calls this, we need to do it here too in
797 // case of a crash.
798 Deactivated();
800 if (why == AbnormalShutdown) {
801 // dom_reporting_header must also be enabled for the report to be sent.
802 if (StaticPrefs::dom_reporting_crash_enabled()) {
803 nsCOMPtr<nsIPrincipal> principal = GetContentPrincipal();
805 if (principal) {
806 nsAutoCString crash_reason;
807 CrashReporter::GetAnnotation(OtherPid(),
808 CrashReporter::Annotation::MozCrashReason,
809 crash_reason);
810 // FIXME(arenevier): Find a less fragile way to identify that a crash
811 // was caused by OOM
812 bool is_oom = false;
813 if (crash_reason == "OOM" || crash_reason == "OOM!" ||
814 StringBeginsWith(crash_reason, "[unhandlable oom]"_ns) ||
815 StringBeginsWith(crash_reason, "Unhandlable OOM"_ns)) {
816 is_oom = true;
819 CrashReport::Deliver(principal, is_oom);
824 // If we were shutting down normally, we held a reference to our
825 // BrowsingContextGroup in `BrowserParent::Destroy`. Clear that reference
826 // here.
827 if (mMarkedDestroying) {
828 mBrowsingContext->Group()->RemoveKeepAlive();
831 // Tell our embedder that the tab is now going away unless we're an
832 // out-of-process iframe.
833 RefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
834 if (frameLoader) {
835 ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr);
837 if (mBrowsingContext->IsTop()) {
838 // If this is a top-level BrowsingContext, tell the frameloader it's time
839 // to go away. Otherwise, this is a subframe crash, and we can keep the
840 // frameloader around.
841 frameLoader->DestroyComplete();
844 // If this was a crash, tell our nsFrameLoader to fire crash events.
845 if (why == AbnormalShutdown) {
846 frameLoader->MaybeNotifyCrashed(mBrowsingContext, Manager()->ChildID(),
847 GetIPCChannel());
848 } else if (why == ManagedEndpointDropped) {
849 // If we instead failed due to a constructor error, don't include process
850 // information, as the process did not crash.
851 frameLoader->MaybeNotifyCrashed(mBrowsingContext, ContentParentId{},
852 nullptr);
856 mFrameLoader = nullptr;
858 // If we were destroyed due to our ManagedEndpoints being dropped, make a
859 // point of showing the subframe crashed UI. We don't fire the full
860 // `MaybeNotifyCrashed` codepath, as the entire process hasn't crashed on us,
861 // and it may confuse the frontend.
862 mBrowsingContext->BrowserParentDestroyed(
863 this, why == AbnormalShutdown || why == ManagedEndpointDropped);
866 mozilla::ipc::IPCResult BrowserParent::RecvMoveFocus(
867 const bool& aForward, const bool& aForDocumentNavigation) {
868 LOGBROWSERFOCUS(("RecvMoveFocus %p, aForward: %d, aForDocumentNavigation: %d",
869 this, aForward, aForDocumentNavigation));
870 BrowserBridgeParent* bridgeParent = GetBrowserBridgeParent();
871 if (bridgeParent) {
872 mozilla::Unused << bridgeParent->SendMoveFocus(aForward,
873 aForDocumentNavigation);
874 return IPC_OK();
877 RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager();
878 if (fm) {
879 RefPtr<Element> dummy;
881 uint32_t type =
882 aForward
883 ? (aForDocumentNavigation
884 ? static_cast<uint32_t>(
885 nsIFocusManager::MOVEFOCUS_FORWARDDOC)
886 : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARD))
887 : (aForDocumentNavigation
888 ? static_cast<uint32_t>(
889 nsIFocusManager::MOVEFOCUS_BACKWARDDOC)
890 : static_cast<uint32_t>(
891 nsIFocusManager::MOVEFOCUS_BACKWARD));
892 fm->MoveFocus(nullptr, mFrameElement, type, nsIFocusManager::FLAG_BYKEY,
893 getter_AddRefs(dummy));
895 return IPC_OK();
898 mozilla::ipc::IPCResult BrowserParent::RecvDropLinks(
899 nsTArray<nsString>&& aLinks) {
900 nsCOMPtr<nsIBrowser> browser =
901 mFrameElement ? mFrameElement->AsBrowser() : nullptr;
902 if (browser) {
903 // Verify that links have not been modified by the child. If links have
904 // not been modified then it's safe to load those links using the
905 // SystemPrincipal. If they have been modified by web content, then
906 // we use a NullPrincipal which still allows to load web links.
907 bool loadUsingSystemPrincipal = true;
908 if (aLinks.Length() != mVerifyDropLinks.Length()) {
909 loadUsingSystemPrincipal = false;
911 for (uint32_t i = 0; i < aLinks.Length(); i++) {
912 if (loadUsingSystemPrincipal) {
913 if (!aLinks[i].Equals(mVerifyDropLinks[i])) {
914 loadUsingSystemPrincipal = false;
918 mVerifyDropLinks.Clear();
919 nsCOMPtr<nsIPrincipal> triggeringPrincipal;
920 if (loadUsingSystemPrincipal) {
921 triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
922 } else {
923 triggeringPrincipal = NullPrincipal::CreateWithoutOriginAttributes();
925 browser->DropLinks(aLinks, triggeringPrincipal);
927 return IPC_OK();
930 bool BrowserParent::SendLoadRemoteScript(const nsAString& aURL,
931 const bool& aRunInGlobalScope) {
932 if (mCreatingWindow) {
933 mDelayedFrameScripts.AppendElement(
934 FrameScriptInfo(nsString(aURL), aRunInGlobalScope));
935 return true;
938 MOZ_ASSERT(mDelayedFrameScripts.IsEmpty());
939 return PBrowserParent::SendLoadRemoteScript(aURL, aRunInGlobalScope);
942 void BrowserParent::LoadURL(nsDocShellLoadState* aLoadState) {
943 MOZ_ASSERT(aLoadState);
944 MOZ_ASSERT(aLoadState->URI());
945 if (mIsDestroyed) {
946 return;
949 if (mCreatingWindow) {
950 // Don't send the message if the child wants to load its own URL.
951 return;
954 Unused << SendLoadURL(WrapNotNull(aLoadState), GetShowInfo());
957 void BrowserParent::ResumeLoad(uint64_t aPendingSwitchID) {
958 MOZ_ASSERT(aPendingSwitchID != 0);
960 if (NS_WARN_IF(mIsDestroyed)) {
961 return;
964 Unused << SendResumeLoad(aPendingSwitchID, GetShowInfo());
967 void BrowserParent::InitRendering() {
968 if (mRemoteLayerTreeOwner.IsInitialized()) {
969 return;
971 mRemoteLayerTreeOwner.Initialize(this);
973 layers::LayersId layersId = mRemoteLayerTreeOwner.GetLayersId();
974 AddBrowserParentToTable(layersId, this);
976 RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
977 if (frameLoader) {
978 nsIFrame* frame = frameLoader->GetPrimaryFrameOfOwningContent();
979 if (frame) {
980 frame->InvalidateFrame();
984 TextureFactoryIdentifier textureFactoryIdentifier;
985 mRemoteLayerTreeOwner.GetTextureFactoryIdentifier(&textureFactoryIdentifier);
986 Unused << SendInitRendering(textureFactoryIdentifier, layersId,
987 mRemoteLayerTreeOwner.GetCompositorOptions(),
988 mRemoteLayerTreeOwner.IsLayersConnected());
990 RefPtr<nsIWidget> widget = GetTopLevelWidget();
991 if (widget) {
992 ScreenIntMargin safeAreaInsets = widget->GetSafeAreaInsets();
993 Unused << SendSafeAreaInsetsChanged(safeAreaInsets);
996 #if defined(MOZ_WIDGET_ANDROID)
997 MOZ_ASSERT(widget);
999 if (GetBrowsingContext()->IsTopContent()) {
1000 Unused << SendDynamicToolbarMaxHeightChanged(
1001 widget->GetDynamicToolbarMaxHeight());
1003 #endif
1006 bool BrowserParent::AttachWindowRenderer() {
1007 return mRemoteLayerTreeOwner.AttachWindowRenderer();
1010 void BrowserParent::MaybeShowFrame() {
1011 RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
1012 if (!frameLoader) {
1013 return;
1015 frameLoader->MaybeShowFrame();
1018 bool BrowserParent::Show(const OwnerShowInfo& aOwnerInfo) {
1019 mDimensions = aOwnerInfo.size();
1020 if (mIsDestroyed) {
1021 return false;
1024 MOZ_ASSERT(mRemoteLayerTreeOwner.IsInitialized());
1025 if (!mRemoteLayerTreeOwner.AttachWindowRenderer()) {
1026 return false;
1029 mSizeMode = aOwnerInfo.sizeMode();
1030 Unused << SendShow(GetShowInfo(), aOwnerInfo);
1031 return true;
1034 mozilla::ipc::IPCResult BrowserParent::RecvSetDimensions(
1035 mozilla::DimensionRequest aRequest, const double& aScale) {
1036 NS_ENSURE_TRUE(mFrameElement, IPC_OK());
1037 nsCOMPtr<nsIDocShell> docShell = mFrameElement->OwnerDoc()->GetDocShell();
1038 NS_ENSURE_TRUE(docShell, IPC_OK());
1039 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
1040 docShell->GetTreeOwner(getter_AddRefs(treeOwner));
1041 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = do_QueryInterface(treeOwner);
1042 NS_ENSURE_TRUE(treeOwnerAsWin, IPC_OK());
1044 // `BrowserChild` only sends the values to actually be changed, see more
1045 // details in `BrowserChild::SetDimensions()`.
1046 // Note that `BrowserChild::SetDimensions()` may be called before receiving
1047 // our `SendUIResolutionChanged()` call. Therefore, if given each coordinate
1048 // shouldn't be ignored, we need to recompute it if DPI has been changed.
1049 // And also note that don't use `mDefaultScale.scale` here since it may be
1050 // different from the result of `GetWidgetCSSToDeviceScale()`.
1051 // NOTE(emilio): We use GetWidgetCSSToDeviceScale() because the old scale is a
1052 // widget scale, and we only use the current scale to scale up/down the
1053 // relevant values.
1055 CSSToLayoutDeviceScale oldScale((float)aScale);
1056 CSSToLayoutDeviceScale currentScale(
1057 (float)treeOwnerAsWin->GetWidgetCSSToDeviceScale());
1059 if (oldScale != currentScale) {
1060 auto rescaleFunc = [&oldScale, &currentScale](LayoutDeviceIntCoord& aVal) {
1061 aVal = (LayoutDeviceCoord(aVal) / oldScale * currentScale).Rounded();
1063 aRequest.mX.apply(rescaleFunc);
1064 aRequest.mY.apply(rescaleFunc);
1065 aRequest.mWidth.apply(rescaleFunc);
1066 aRequest.mHeight.apply(rescaleFunc);
1069 // treeOwner is the chrome tree owner, but we wan't the content tree owner.
1070 nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = do_GetInterface(treeOwner);
1071 NS_ENSURE_TRUE(webBrowserChrome, IPC_OK());
1072 webBrowserChrome->SetDimensions(std::move(aRequest));
1073 return IPC_OK();
1076 nsresult BrowserParent::UpdatePosition() {
1077 RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
1078 if (!frameLoader) {
1079 return NS_OK;
1081 nsIntRect windowDims;
1082 NS_ENSURE_SUCCESS(frameLoader->GetWindowDimensions(windowDims),
1083 NS_ERROR_FAILURE);
1084 // Avoid updating sizes here.
1085 windowDims.SizeTo(mRect.Size());
1086 UpdateDimensions(windowDims, mDimensions);
1087 return NS_OK;
1090 void BrowserParent::NotifyPositionUpdatedForContentsInPopup() {
1091 if (CanonicalBrowsingContext* bc = GetBrowsingContext()) {
1092 bc->PreOrderWalk([](BrowsingContext* aContext) {
1093 if (WindowGlobalParent* windowGlobalParent =
1094 aContext->Canonical()->GetCurrentWindowGlobal()) {
1095 if (RefPtr<BrowserParent> browserParent =
1096 windowGlobalParent->GetBrowserParent()) {
1097 browserParent->UpdatePosition();
1104 void BrowserParent::UpdateDimensions(const nsIntRect& rect,
1105 const ScreenIntSize& size) {
1106 if (mIsDestroyed) {
1107 return;
1109 nsCOMPtr<nsIWidget> widget = GetWidget();
1110 if (!widget) {
1111 NS_WARNING("No widget found in BrowserParent::UpdateDimensions");
1112 return;
1115 LayoutDeviceIntPoint clientOffset = GetClientOffset();
1116 LayoutDeviceIntPoint chromeOffset = !GetBrowserBridgeParent()
1117 ? -GetChildProcessOffset()
1118 : LayoutDeviceIntPoint();
1120 if (!mUpdatedDimensions || mDimensions != size || !mRect.IsEqualEdges(rect) ||
1121 clientOffset != mClientOffset || chromeOffset != mChromeOffset) {
1122 mUpdatedDimensions = true;
1123 mRect = rect;
1124 mDimensions = size;
1125 mClientOffset = clientOffset;
1126 mChromeOffset = chromeOffset;
1128 Unused << SendUpdateDimensions(GetDimensionInfo());
1129 UpdateNativePointerLockCenter(widget);
1133 DimensionInfo BrowserParent::GetDimensionInfo() {
1134 LayoutDeviceIntRect devicePixelRect = ViewAs<LayoutDevicePixel>(
1135 mRect, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
1136 LayoutDeviceIntSize devicePixelSize = ViewAs<LayoutDevicePixel>(
1137 mDimensions, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
1139 CSSRect unscaledRect = devicePixelRect / mDefaultScale;
1140 CSSSize unscaledSize = devicePixelSize / mDefaultScale;
1141 DimensionInfo di(unscaledRect, unscaledSize, mClientOffset, mChromeOffset);
1142 return di;
1145 void BrowserParent::UpdateNativePointerLockCenter(nsIWidget* aWidget) {
1146 if (!mLockedNativePointer) {
1147 return;
1149 LayoutDeviceIntRect dims(
1150 {0, 0},
1151 ViewAs<LayoutDevicePixel>(
1152 mDimensions, PixelCastJustification::LayoutDeviceIsScreenForTabDims));
1153 aWidget->SetNativePointerLockCenter((dims + mChromeOffset).Center());
1156 void BrowserParent::SizeModeChanged(const nsSizeMode& aSizeMode) {
1157 if (!mIsDestroyed && aSizeMode != mSizeMode) {
1158 mSizeMode = aSizeMode;
1159 Unused << SendSizeModeChanged(aSizeMode);
1163 #if defined(MOZ_WIDGET_ANDROID)
1164 void BrowserParent::DynamicToolbarMaxHeightChanged(ScreenIntCoord aHeight) {
1165 if (!mIsDestroyed) {
1166 Unused << SendDynamicToolbarMaxHeightChanged(aHeight);
1170 void BrowserParent::DynamicToolbarOffsetChanged(ScreenIntCoord aOffset) {
1171 if (!mIsDestroyed) {
1172 Unused << SendDynamicToolbarOffsetChanged(aOffset);
1175 #endif
1177 void BrowserParent::HandleAccessKey(const WidgetKeyboardEvent& aEvent,
1178 nsTArray<uint32_t>& aCharCodes) {
1179 if (!mIsDestroyed) {
1180 // Note that we don't need to mark aEvent is posted to a remote process
1181 // because the event may be dispatched to it as normal keyboard event.
1182 // Therefore, we should use local copy to send it.
1183 WidgetKeyboardEvent localEvent(aEvent);
1184 RequestingAccessKeyEventData::Set(localEvent);
1185 Unused << SendHandleAccessKey(localEvent, aCharCodes);
1189 void BrowserParent::Activate(uint64_t aActionId) {
1190 LOGBROWSERFOCUS(("Activate %p actionid: %" PRIu64, this, aActionId));
1191 if (!mIsDestroyed) {
1192 SetTopLevelWebFocus(this); // Intentionally inside "if"
1193 Unused << SendActivate(aActionId);
1197 void BrowserParent::Deactivate(bool aWindowLowering, uint64_t aActionId) {
1198 LOGBROWSERFOCUS(("Deactivate %p actionid: %" PRIu64, this, aActionId));
1199 if (!aWindowLowering) {
1200 UnsetTopLevelWebFocus(this); // Intentionally outside the next "if"
1202 if (!mIsDestroyed) {
1203 Unused << SendDeactivate(aActionId);
1207 #ifdef ACCESSIBILITY
1208 a11y::PDocAccessibleParent* BrowserParent::AllocPDocAccessibleParent(
1209 PDocAccessibleParent* aParent, const uint64_t&,
1210 const MaybeDiscardedBrowsingContext&) {
1211 // Reference freed in DeallocPDocAccessibleParent.
1212 return a11y::DocAccessibleParent::New().take();
1215 bool BrowserParent::DeallocPDocAccessibleParent(PDocAccessibleParent* aParent) {
1216 // Free reference from AllocPDocAccessibleParent.
1217 static_cast<a11y::DocAccessibleParent*>(aParent)->Release();
1218 return true;
1221 mozilla::ipc::IPCResult BrowserParent::RecvPDocAccessibleConstructor(
1222 PDocAccessibleParent* aDoc, PDocAccessibleParent* aParentDoc,
1223 const uint64_t& aParentID,
1224 const MaybeDiscardedBrowsingContext& aBrowsingContext) {
1225 # if defined(ANDROID)
1226 MonitorAutoLock mal(nsAccessibilityService::GetAndroidMonitor());
1227 # endif
1228 auto doc = static_cast<a11y::DocAccessibleParent*>(aDoc);
1230 // If this tab is already shutting down just mark the new actor as shutdown
1231 // and ignore it. When the tab actor is destroyed it will be too.
1232 if (mIsDestroyed) {
1233 doc->MarkAsShutdown();
1234 return IPC_OK();
1237 if (aParentDoc) {
1238 // Iframe document rendered in the same process as its embedder.
1239 // A document should never directly be the parent of another document.
1240 // There should always be an outer doc accessible child of the outer
1241 // document containing the child.
1242 MOZ_ASSERT(aParentID);
1243 if (!aParentID) {
1244 return IPC_FAIL_NO_REASON(this);
1247 auto parentDoc = static_cast<a11y::DocAccessibleParent*>(aParentDoc);
1248 if (parentDoc->IsShutdown()) {
1249 // This can happen if parentDoc is an OOP iframe, but its embedder has
1250 // been destroyed. (DocAccessibleParent::Destroy destroys any child
1251 // documents.) The OOP iframe (and anything it embeds) will die soon
1252 // anyway, so mark this document as shutdown and ignore it.
1253 doc->MarkAsShutdown();
1254 return IPC_OK();
1257 if (aBrowsingContext) {
1258 doc->SetBrowsingContext(aBrowsingContext.get_canonical());
1261 mozilla::ipc::IPCResult added = parentDoc->AddChildDoc(doc, aParentID);
1262 if (!added) {
1263 # ifdef DEBUG
1264 return added;
1265 # else
1266 return IPC_OK();
1267 # endif
1270 # ifdef XP_WIN
1271 if (a11y::nsWinUtils::IsWindowEmulationStarted()) {
1272 doc->SetEmulatedWindowHandle(parentDoc->GetEmulatedWindowHandle());
1274 # endif
1276 return IPC_OK();
1279 if (aBrowsingContext) {
1280 doc->SetBrowsingContext(aBrowsingContext.get_canonical());
1283 if (auto* bridge = GetBrowserBridgeParent()) {
1284 // Iframe document rendered in a different process to its embedder.
1285 // In this case, we don't get aParentDoc and aParentID.
1286 MOZ_ASSERT(!aParentDoc && !aParentID);
1287 doc->SetTopLevelInContentProcess();
1288 a11y::ProxyCreated(doc);
1289 // It's possible the embedder accessible hasn't been set yet; e.g.
1290 // a hidden iframe. In that case, embedderDoc will be null and this will
1291 // be handled when the embedder is set.
1292 if (a11y::DocAccessibleParent* embedderDoc =
1293 bridge->GetEmbedderAccessibleDoc()) {
1294 mozilla::ipc::IPCResult added = embedderDoc->AddChildDoc(bridge);
1295 if (!added) {
1296 # ifdef DEBUG
1297 return added;
1298 # else
1299 return IPC_OK();
1300 # endif
1303 return IPC_OK();
1304 } else {
1305 // null aParentDoc means this document is at the top level in the child
1306 // process. That means it makes no sense to get an id for an accessible
1307 // that is its parent.
1308 MOZ_ASSERT(!aParentID);
1309 if (aParentID) {
1310 return IPC_FAIL_NO_REASON(this);
1313 if (auto* prevTopLevel = GetTopLevelDocAccessible()) {
1314 // Sometimes, we can get a new top level DocAccessibleParent before the
1315 // old one gets destroyed. The old one will die pretty shortly anyway,
1316 // so just destroy it now. If we don't do this, GetTopLevelDocAccessible()
1317 // might return the wrong document for a short while.
1318 prevTopLevel->Destroy();
1320 doc->SetTopLevel();
1321 a11y::DocManager::RemoteDocAdded(doc);
1322 # ifdef XP_WIN
1323 doc->MaybeInitWindowEmulation();
1324 # endif
1326 return IPC_OK();
1328 #endif
1330 already_AddRefed<PFilePickerParent> BrowserParent::AllocPFilePickerParent(
1331 const nsString& aTitle, const nsIFilePicker::Mode& aMode) {
1332 return MakeAndAddRef<FilePickerParent>(aTitle, aMode);
1335 already_AddRefed<PSessionStoreParent>
1336 BrowserParent::AllocPSessionStoreParent() {
1337 RefPtr<BrowserSessionStore> sessionStore =
1338 BrowserSessionStore::GetOrCreate(mBrowsingContext->Top());
1339 if (!sessionStore) {
1340 return nullptr;
1343 return do_AddRef(new SessionStoreParent(mBrowsingContext, sessionStore));
1346 IPCResult BrowserParent::RecvNewWindowGlobal(
1347 ManagedEndpoint<PWindowGlobalParent>&& aEndpoint,
1348 const WindowGlobalInit& aInit) {
1349 RefPtr<CanonicalBrowsingContext> browsingContext =
1350 CanonicalBrowsingContext::Get(aInit.context().mBrowsingContextId);
1351 if (!browsingContext) {
1352 return IPC_FAIL(this, "Cannot create for missing BrowsingContext");
1354 if (!aInit.principal()) {
1355 return IPC_FAIL(this, "Cannot create without valid principal");
1358 // Ensure we never load a document with a content principal in
1359 // the wrong type of webIsolated process
1360 EnumSet<ContentParent::ValidatePrincipalOptions> validationOptions = {};
1361 nsCOMPtr<nsIURI> docURI = aInit.documentURI();
1362 if (docURI->SchemeIs("about") || docURI->SchemeIs("blob") ||
1363 docURI->SchemeIs("chrome")) {
1364 // XXXckerschb TODO - Do not use SystemPrincipal for:
1365 // Bug 1700639: about:plugins
1366 // Bug 1699385: Remove allowSystem for blobs
1367 // Bug 1698087: chrome://devtools/content/shared/webextension-fallback.html
1368 // chrome reftests, e.g.
1369 // * chrome://reftest/content/writing-mode/ua-style-sheet-button-1a-ref.html
1370 // * chrome://reftest/content/xul-document-load/test003.xhtml
1371 // * chrome://reftest/content/forms/input/text/centering-1.xhtml
1372 validationOptions = {ContentParent::ValidatePrincipalOptions::AllowSystem};
1375 if (!mManager->ValidatePrincipal(aInit.principal(), validationOptions)) {
1376 ContentParent::LogAndAssertFailedPrincipalValidationInfo(aInit.principal(),
1377 __func__);
1380 // Construct our new WindowGlobalParent, bind, and initialize it.
1381 RefPtr<WindowGlobalParent> wgp =
1382 WindowGlobalParent::CreateDisconnected(aInit);
1383 BindPWindowGlobalEndpoint(std::move(aEndpoint), wgp);
1384 wgp->Init();
1385 return IPC_OK();
1388 PVsyncParent* BrowserParent::AllocPVsyncParent() {
1389 MOZ_ASSERT(!mVsyncParent);
1390 mVsyncParent = new VsyncParent();
1391 UpdateVsyncParentVsyncDispatcher();
1392 return mVsyncParent.get();
1395 bool BrowserParent::DeallocPVsyncParent(PVsyncParent* aActor) {
1396 MOZ_ASSERT(aActor);
1397 mVsyncParent = nullptr;
1398 return true;
1401 void BrowserParent::UpdateVsyncParentVsyncDispatcher() {
1402 if (!mVsyncParent) {
1403 return;
1406 if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
1407 RefPtr<VsyncDispatcher> vsyncDispatcher = widget->GetVsyncDispatcher();
1408 if (!vsyncDispatcher) {
1409 vsyncDispatcher = gfxPlatform::GetPlatform()->GetGlobalVsyncDispatcher();
1411 mVsyncParent->UpdateVsyncDispatcher(vsyncDispatcher);
1415 void BrowserParent::MouseEnterIntoWidget() {
1416 if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
1417 // When we mouseenter the remote target, the remote target's cursor should
1418 // become the current cursor. When we mouseexit, we stop.
1419 mRemoteTargetSetsCursor = true;
1420 widget->SetCursor(mCursor);
1423 // Mark that we have missed a mouse enter event, so that
1424 // the next mouse event will create a replacement mouse
1425 // enter event and send it to the child.
1426 mIsMouseEnterIntoWidgetEventSuppressed = true;
1429 void BrowserParent::SendRealMouseEvent(WidgetMouseEvent& aEvent) {
1430 if (mIsDestroyed) {
1431 return;
1434 // XXXedgar, if the synthesized mouse events could deliver to the correct
1435 // process directly (see
1436 // https://bugzilla.mozilla.org/show_bug.cgi?id=1549355), we probably don't
1437 // need to check mReason then.
1438 if (aEvent.mReason == WidgetMouseEvent::eReal) {
1439 if (aEvent.mMessage == eMouseExitFromWidget) {
1440 // Since we are leaving this remote target, so don't need to update
1441 // sLastMouseRemoteTarget, and if we are sLastMouseRemoteTarget, reset it
1442 // to null.
1443 BrowserParent::UnsetLastMouseRemoteTarget(this);
1444 } else {
1445 // Last remote target should not be changed without eMouseExitFromWidget.
1446 MOZ_ASSERT_IF(sLastMouseRemoteTarget, sLastMouseRemoteTarget == this);
1447 sLastMouseRemoteTarget = this;
1451 aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
1453 nsCOMPtr<nsIWidget> widget = GetWidget();
1454 if (widget) {
1455 // When we mouseenter the remote target, the remote target's cursor should
1456 // become the current cursor. When we mouseexit, we stop.
1457 if (eMouseEnterIntoWidget == aEvent.mMessage) {
1458 mRemoteTargetSetsCursor = true;
1459 widget->SetCursor(mCursor);
1460 } else if (eMouseExitFromWidget == aEvent.mMessage) {
1461 mRemoteTargetSetsCursor = false;
1464 if (!mIsReadyToHandleInputEvents) {
1465 if (eMouseEnterIntoWidget == aEvent.mMessage) {
1466 mIsMouseEnterIntoWidgetEventSuppressed = true;
1467 } else if (eMouseExitFromWidget == aEvent.mMessage) {
1468 mIsMouseEnterIntoWidgetEventSuppressed = false;
1470 return;
1473 ScrollableLayerGuid guid;
1474 uint64_t blockId;
1475 ApzAwareEventRoutingToChild(&guid, &blockId, nullptr);
1477 bool isInputPriorityEventEnabled = Manager()->IsInputPriorityEventEnabled();
1479 if (mIsMouseEnterIntoWidgetEventSuppressed) {
1480 // In the case that the BrowserParent suppressed the eMouseEnterWidget event
1481 // due to its corresponding BrowserChild wasn't ready to handle it, we have
1482 // to resend it when the BrowserChild is ready.
1483 mIsMouseEnterIntoWidgetEventSuppressed = false;
1484 WidgetMouseEvent localEvent(aEvent);
1485 localEvent.mMessage = eMouseEnterIntoWidget;
1486 DebugOnly<bool> ret =
1487 isInputPriorityEventEnabled
1488 ? SendRealMouseEnterExitWidgetEvent(localEvent, guid, blockId)
1489 : SendNormalPriorityRealMouseEnterExitWidgetEvent(localEvent, guid,
1490 blockId);
1491 NS_WARNING_ASSERTION(ret, "SendRealMouseEnterExitWidgetEvent() failed");
1492 MOZ_ASSERT(!ret || localEvent.HasBeenPostedToRemoteProcess());
1495 if (eMouseMove == aEvent.mMessage) {
1496 if (aEvent.mReason == WidgetMouseEvent::eSynthesized) {
1497 DebugOnly<bool> ret =
1498 isInputPriorityEventEnabled
1499 ? SendSynthMouseMoveEvent(aEvent, guid, blockId)
1500 : SendNormalPrioritySynthMouseMoveEvent(aEvent, guid, blockId);
1501 NS_WARNING_ASSERTION(ret, "SendSynthMouseMoveEvent() failed");
1502 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
1503 return;
1506 if (!aEvent.mFlags.mIsSynthesizedForTests) {
1507 DebugOnly<bool> ret =
1508 isInputPriorityEventEnabled
1509 ? SendRealMouseMoveEvent(aEvent, guid, blockId)
1510 : SendNormalPriorityRealMouseMoveEvent(aEvent, guid, blockId);
1511 NS_WARNING_ASSERTION(ret, "SendRealMouseMoveEvent() failed");
1512 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
1513 return;
1516 DebugOnly<bool> ret =
1517 isInputPriorityEventEnabled
1518 ? SendRealMouseMoveEventForTests(aEvent, guid, blockId)
1519 : SendNormalPriorityRealMouseMoveEventForTests(aEvent, guid,
1520 blockId);
1521 NS_WARNING_ASSERTION(ret, "SendRealMouseMoveEventForTests() failed");
1522 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
1523 return;
1526 if (eMouseEnterIntoWidget == aEvent.mMessage ||
1527 eMouseExitFromWidget == aEvent.mMessage) {
1528 DebugOnly<bool> ret =
1529 isInputPriorityEventEnabled
1530 ? SendRealMouseEnterExitWidgetEvent(aEvent, guid, blockId)
1531 : SendNormalPriorityRealMouseEnterExitWidgetEvent(aEvent, guid,
1532 blockId);
1533 NS_WARNING_ASSERTION(ret, "SendRealMouseEnterExitWidgetEvent() failed");
1534 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
1535 return;
1538 DebugOnly<bool> ret =
1539 isInputPriorityEventEnabled
1540 ? SendRealMouseButtonEvent(aEvent, guid, blockId)
1541 : SendNormalPriorityRealMouseButtonEvent(aEvent, guid, blockId);
1542 NS_WARNING_ASSERTION(ret, "SendRealMouseButtonEvent() failed");
1543 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
1546 LayoutDeviceToCSSScale BrowserParent::GetLayoutDeviceToCSSScale() {
1547 Document* doc = (mFrameElement ? mFrameElement->OwnerDoc() : nullptr);
1548 nsPresContext* ctx = (doc ? doc->GetPresContext() : nullptr);
1549 return LayoutDeviceToCSSScale(
1550 ctx ? (float)ctx->AppUnitsPerDevPixel() / AppUnitsPerCSSPixel() : 0.0f);
1553 bool BrowserParent::QueryDropLinksForVerification() {
1554 // Before sending the dragEvent, we query the links being dragged and
1555 // store them on the parent, to make sure the child can not modify links.
1556 nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
1557 if (!dragSession) {
1558 NS_WARNING("No dragSession to query links for verification");
1559 return false;
1562 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
1563 if (!initialDataTransfer) {
1564 NS_WARNING("No initialDataTransfer to query links for verification");
1565 return false;
1568 nsCOMPtr<nsIDroppedLinkHandler> dropHandler =
1569 do_GetService("@mozilla.org/content/dropped-link-handler;1");
1570 if (!dropHandler) {
1571 NS_WARNING("No dropHandler to query links for verification");
1572 return false;
1575 // No more than one drop event can happen simultaneously; reset the link
1576 // verification array and store all links that are being dragged.
1577 mVerifyDropLinks.Clear();
1579 nsTArray<RefPtr<nsIDroppedLinkItem>> droppedLinkItems;
1580 dropHandler->QueryLinks(initialDataTransfer, droppedLinkItems);
1582 // Since the entire event is cancelled if one of the links is invalid,
1583 // we can store all links on the parent side without any prior
1584 // validation checks.
1585 nsresult rv = NS_OK;
1586 for (nsIDroppedLinkItem* item : droppedLinkItems) {
1587 nsString tmp;
1588 rv = item->GetUrl(tmp);
1589 if (NS_FAILED(rv)) {
1590 NS_WARNING("Failed to query url for verification");
1591 break;
1593 mVerifyDropLinks.AppendElement(tmp);
1595 rv = item->GetName(tmp);
1596 if (NS_FAILED(rv)) {
1597 NS_WARNING("Failed to query name for verification");
1598 break;
1600 mVerifyDropLinks.AppendElement(tmp);
1602 rv = item->GetType(tmp);
1603 if (NS_FAILED(rv)) {
1604 NS_WARNING("Failed to query type for verification");
1605 break;
1607 mVerifyDropLinks.AppendElement(tmp);
1609 if (NS_FAILED(rv)) {
1610 mVerifyDropLinks.Clear();
1611 return false;
1613 return true;
1616 void BrowserParent::SendRealDragEvent(WidgetDragEvent& aEvent,
1617 uint32_t aDragAction,
1618 uint32_t aDropEffect,
1619 nsIPrincipal* aPrincipal,
1620 nsIContentSecurityPolicy* aCsp) {
1621 if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
1622 return;
1624 MOZ_ASSERT(!Manager()->IsInputPriorityEventEnabled());
1625 aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
1626 if (aEvent.mMessage == eDrop) {
1627 if (!QueryDropLinksForVerification()) {
1628 return;
1631 DebugOnly<bool> ret = PBrowserParent::SendRealDragEvent(
1632 aEvent, aDragAction, aDropEffect, aPrincipal, aCsp);
1633 NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealDragEvent() failed");
1634 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
1637 void BrowserParent::SendMouseWheelEvent(WidgetWheelEvent& aEvent) {
1638 if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
1639 return;
1642 ScrollableLayerGuid guid;
1643 uint64_t blockId;
1644 ApzAwareEventRoutingToChild(&guid, &blockId, nullptr);
1645 aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
1646 DebugOnly<bool> ret =
1647 Manager()->IsInputPriorityEventEnabled()
1648 ? PBrowserParent::SendMouseWheelEvent(aEvent, guid, blockId)
1649 : PBrowserParent::SendNormalPriorityMouseWheelEvent(aEvent, guid,
1650 blockId);
1652 NS_WARNING_ASSERTION(ret, "PBrowserParent::SendMouseWheelEvent() failed");
1653 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
1656 mozilla::ipc::IPCResult BrowserParent::RecvDispatchWheelEvent(
1657 const mozilla::WidgetWheelEvent& aEvent) {
1658 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1660 nsCOMPtr<nsIWidget> widget = GetWidget();
1661 if (!widget) {
1662 return IPC_OK();
1665 WidgetWheelEvent localEvent(aEvent);
1666 localEvent.mWidget = widget;
1667 localEvent.mRefPoint = TransformChildToParent(localEvent.mRefPoint);
1669 widget->DispatchInputEvent(&localEvent);
1670 return IPC_OK();
1673 mozilla::ipc::IPCResult BrowserParent::RecvDispatchMouseEvent(
1674 const mozilla::WidgetMouseEvent& aEvent) {
1675 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1677 nsCOMPtr<nsIWidget> widget = GetWidget();
1678 if (!widget) {
1679 return IPC_OK();
1682 WidgetMouseEvent localEvent(aEvent);
1683 localEvent.mWidget = widget;
1684 localEvent.mRefPoint = TransformChildToParent(localEvent.mRefPoint);
1686 widget->DispatchInputEvent(&localEvent);
1687 return IPC_OK();
1690 mozilla::ipc::IPCResult BrowserParent::RecvDispatchKeyboardEvent(
1691 const mozilla::WidgetKeyboardEvent& aEvent) {
1692 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1694 nsCOMPtr<nsIWidget> widget = GetWidget();
1695 if (!widget) {
1696 return IPC_OK();
1699 WidgetKeyboardEvent localEvent(aEvent);
1700 localEvent.mWidget = widget;
1701 localEvent.mRefPoint = TransformChildToParent(localEvent.mRefPoint);
1703 widget->DispatchInputEvent(&localEvent);
1704 return IPC_OK();
1707 mozilla::ipc::IPCResult BrowserParent::RecvDispatchTouchEvent(
1708 const mozilla::WidgetTouchEvent& aEvent) {
1709 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1711 nsCOMPtr<nsIWidget> widget = GetWidget();
1712 if (!widget) {
1713 return IPC_OK();
1716 WidgetTouchEvent localEvent(aEvent);
1717 localEvent.mWidget = widget;
1719 for (uint32_t i = 0; i < localEvent.mTouches.Length(); i++) {
1720 localEvent.mTouches[i]->mRefPoint =
1721 TransformChildToParent(localEvent.mTouches[i]->mRefPoint);
1724 widget->DispatchInputEvent(&localEvent);
1725 return IPC_OK();
1728 mozilla::ipc::IPCResult BrowserParent::RecvRequestNativeKeyBindings(
1729 const uint32_t& aType, const WidgetKeyboardEvent& aEvent,
1730 nsTArray<CommandInt>* aCommands) {
1731 MOZ_ASSERT(aCommands);
1732 MOZ_ASSERT(aCommands->IsEmpty());
1734 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1736 NativeKeyBindingsType keyBindingsType =
1737 static_cast<NativeKeyBindingsType>(aType);
1738 switch (keyBindingsType) {
1739 case NativeKeyBindingsType::SingleLineEditor:
1740 case NativeKeyBindingsType::MultiLineEditor:
1741 case NativeKeyBindingsType::RichTextEditor:
1742 break;
1743 default:
1744 return IPC_FAIL(this, "Invalid aType value");
1747 nsCOMPtr<nsIWidget> widget = GetWidget();
1748 if (!widget) {
1749 return IPC_OK();
1752 WidgetKeyboardEvent localEvent(aEvent);
1753 localEvent.mWidget = widget;
1755 if (NS_FAILED(widget->AttachNativeKeyEvent(localEvent))) {
1756 return IPC_OK();
1759 Maybe<WritingMode> writingMode;
1760 if (RefPtr<widget::TextEventDispatcher> dispatcher =
1761 widget->GetTextEventDispatcher()) {
1762 writingMode = dispatcher->MaybeQueryWritingModeAtSelection();
1764 if (localEvent.InitEditCommandsFor(keyBindingsType, writingMode)) {
1765 *aCommands = localEvent.EditCommandsConstRef(keyBindingsType).Clone();
1768 return IPC_OK();
1771 class SynthesizedEventObserver : public nsIObserver {
1772 NS_DECL_ISUPPORTS
1774 public:
1775 SynthesizedEventObserver(BrowserParent* aBrowserParent,
1776 const uint64_t& aObserverId)
1777 : mBrowserParent(aBrowserParent), mObserverId(aObserverId) {
1778 MOZ_ASSERT(mBrowserParent);
1781 NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
1782 const char16_t* aData) override {
1783 if (!mBrowserParent || !mObserverId) {
1784 // We already sent the notification, or we don't actually need to
1785 // send any notification at all.
1786 return NS_OK;
1789 if (mBrowserParent->IsDestroyed()) {
1790 // If this happens it's probably a bug in the test that's triggering this.
1791 NS_WARNING(
1792 "BrowserParent was unexpectedly destroyed during event "
1793 "synthesization!");
1794 } else if (!mBrowserParent->SendNativeSynthesisResponse(
1795 mObserverId, nsCString(aTopic))) {
1796 NS_WARNING("Unable to send native event synthesization response!");
1798 // Null out browserParent to indicate we already sent the response
1799 mBrowserParent = nullptr;
1800 return NS_OK;
1803 private:
1804 virtual ~SynthesizedEventObserver() = default;
1806 RefPtr<BrowserParent> mBrowserParent;
1807 uint64_t mObserverId;
1810 NS_IMPL_ISUPPORTS(SynthesizedEventObserver, nsIObserver)
1812 class MOZ_STACK_CLASS AutoSynthesizedEventResponder {
1813 public:
1814 AutoSynthesizedEventResponder(BrowserParent* aBrowserParent,
1815 const uint64_t& aObserverId, const char* aTopic)
1816 : mObserver(new SynthesizedEventObserver(aBrowserParent, aObserverId)),
1817 mTopic(aTopic) {}
1819 ~AutoSynthesizedEventResponder() {
1820 // This may be a no-op if the observer already sent a response.
1821 mObserver->Observe(nullptr, mTopic, nullptr);
1824 nsIObserver* GetObserver() { return mObserver; }
1826 private:
1827 nsCOMPtr<nsIObserver> mObserver;
1828 const char* mTopic;
1831 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeKeyEvent(
1832 const int32_t& aNativeKeyboardLayout, const int32_t& aNativeKeyCode,
1833 const uint32_t& aModifierFlags, const nsString& aCharacters,
1834 const nsString& aUnmodifiedCharacters, const uint64_t& aObserverId) {
1835 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1837 AutoSynthesizedEventResponder responder(this, aObserverId, "keyevent");
1838 nsCOMPtr<nsIWidget> widget = GetWidget();
1839 if (widget) {
1840 widget->SynthesizeNativeKeyEvent(
1841 aNativeKeyboardLayout, aNativeKeyCode, aModifierFlags, aCharacters,
1842 aUnmodifiedCharacters, responder.GetObserver());
1844 return IPC_OK();
1847 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeMouseEvent(
1848 const LayoutDeviceIntPoint& aPoint, const uint32_t& aNativeMessage,
1849 const int16_t& aButton, const uint32_t& aModifierFlags,
1850 const uint64_t& aObserverId) {
1851 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1853 const uint32_t last =
1854 static_cast<uint32_t>(nsIWidget::NativeMouseMessage::LeaveWindow);
1855 NS_ENSURE_TRUE(aNativeMessage <= last, IPC_FAIL(this, "Bogus message"));
1856 AutoSynthesizedEventResponder responder(this, aObserverId, "mouseevent");
1857 nsCOMPtr<nsIWidget> widget = GetWidget();
1858 if (widget) {
1859 widget->SynthesizeNativeMouseEvent(
1860 aPoint, static_cast<nsIWidget::NativeMouseMessage>(aNativeMessage),
1861 static_cast<mozilla::MouseButton>(aButton),
1862 static_cast<nsIWidget::Modifiers>(aModifierFlags),
1863 responder.GetObserver());
1865 return IPC_OK();
1868 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeMouseMove(
1869 const LayoutDeviceIntPoint& aPoint, const uint64_t& aObserverId) {
1870 // This is used by pointer lock API. So, even if it's not in the automation
1871 // mode, we need to accept the request.
1872 AutoSynthesizedEventResponder responder(this, aObserverId, "mousemove");
1873 nsCOMPtr<nsIWidget> widget = GetWidget();
1874 if (widget) {
1875 widget->SynthesizeNativeMouseMove(aPoint, responder.GetObserver());
1877 return IPC_OK();
1880 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeMouseScrollEvent(
1881 const LayoutDeviceIntPoint& aPoint, const uint32_t& aNativeMessage,
1882 const double& aDeltaX, const double& aDeltaY, const double& aDeltaZ,
1883 const uint32_t& aModifierFlags, const uint32_t& aAdditionalFlags,
1884 const uint64_t& aObserverId) {
1885 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1887 AutoSynthesizedEventResponder responder(this, aObserverId,
1888 "mousescrollevent");
1889 nsCOMPtr<nsIWidget> widget = GetWidget();
1890 if (widget) {
1891 widget->SynthesizeNativeMouseScrollEvent(
1892 aPoint, aNativeMessage, aDeltaX, aDeltaY, aDeltaZ, aModifierFlags,
1893 aAdditionalFlags, responder.GetObserver());
1895 return IPC_OK();
1898 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeTouchPoint(
1899 const uint32_t& aPointerId, const TouchPointerState& aPointerState,
1900 const LayoutDeviceIntPoint& aPoint, const double& aPointerPressure,
1901 const uint32_t& aPointerOrientation, const uint64_t& aObserverId) {
1902 // This is used by DevTools to emulate touch events from mouse events in the
1903 // responsive design mode. Therefore, we should accept the IPC messages even
1904 // if it's not in the automation mode but the browsing context is in RDM pane.
1905 // And the IPC message could be just delayed after closing the responsive
1906 // design mode. Therefore, we shouldn't return IPC_FAIL since doing it makes
1907 // the tab crash.
1908 if (!xpc::IsInAutomation()) {
1909 NS_ENSURE_TRUE(mBrowsingContext, IPC_OK());
1910 NS_ENSURE_TRUE(mBrowsingContext->Top()->GetInRDMPane(), IPC_OK());
1913 AutoSynthesizedEventResponder responder(this, aObserverId, "touchpoint");
1914 nsCOMPtr<nsIWidget> widget = GetWidget();
1915 if (widget) {
1916 widget->SynthesizeNativeTouchPoint(aPointerId, aPointerState, aPoint,
1917 aPointerPressure, aPointerOrientation,
1918 responder.GetObserver());
1920 return IPC_OK();
1923 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeTouchPadPinch(
1924 const TouchpadGesturePhase& aEventPhase, const float& aScale,
1925 const LayoutDeviceIntPoint& aPoint, const int32_t& aModifierFlags) {
1926 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1928 nsCOMPtr<nsIWidget> widget = GetWidget();
1929 if (widget) {
1930 widget->SynthesizeNativeTouchPadPinch(aEventPhase, aScale, aPoint,
1931 aModifierFlags);
1933 return IPC_OK();
1936 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeTouchTap(
1937 const LayoutDeviceIntPoint& aPoint, const bool& aLongTap,
1938 const uint64_t& aObserverId) {
1939 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1941 AutoSynthesizedEventResponder responder(this, aObserverId, "touchtap");
1942 nsCOMPtr<nsIWidget> widget = GetWidget();
1943 if (widget) {
1944 widget->SynthesizeNativeTouchTap(aPoint, aLongTap, responder.GetObserver());
1946 return IPC_OK();
1949 mozilla::ipc::IPCResult BrowserParent::RecvClearNativeTouchSequence(
1950 const uint64_t& aObserverId) {
1951 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1953 AutoSynthesizedEventResponder responder(this, aObserverId, "cleartouch");
1954 nsCOMPtr<nsIWidget> widget = GetWidget();
1955 if (widget) {
1956 widget->ClearNativeTouchSequence(responder.GetObserver());
1958 return IPC_OK();
1961 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativePenInput(
1962 const uint32_t& aPointerId, const TouchPointerState& aPointerState,
1963 const LayoutDeviceIntPoint& aPoint, const double& aPressure,
1964 const uint32_t& aRotation, const int32_t& aTiltX, const int32_t& aTiltY,
1965 const int32_t& aButton, const uint64_t& aObserverId) {
1966 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1968 AutoSynthesizedEventResponder responder(this, aObserverId, "peninput");
1969 nsCOMPtr<nsIWidget> widget = GetWidget();
1970 if (widget) {
1971 widget->SynthesizeNativePenInput(aPointerId, aPointerState, aPoint,
1972 aPressure, aRotation, aTiltX, aTiltY,
1973 aButton, responder.GetObserver());
1975 return IPC_OK();
1978 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeTouchpadDoubleTap(
1979 const LayoutDeviceIntPoint& aPoint, const uint32_t& aModifierFlags) {
1980 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1982 nsCOMPtr<nsIWidget> widget = GetWidget();
1983 if (widget) {
1984 widget->SynthesizeNativeTouchpadDoubleTap(aPoint, aModifierFlags);
1986 return IPC_OK();
1989 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeTouchpadPan(
1990 const TouchpadGesturePhase& aEventPhase, const LayoutDeviceIntPoint& aPoint,
1991 const double& aDeltaX, const double& aDeltaY, const int32_t& aModifierFlags,
1992 const uint64_t& aObserverId) {
1993 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1995 AutoSynthesizedEventResponder responder(this, aObserverId,
1996 "touchpadpanevent");
1998 nsCOMPtr<nsIWidget> widget = GetWidget();
1999 if (widget) {
2000 widget->SynthesizeNativeTouchpadPan(aEventPhase, aPoint, aDeltaX, aDeltaY,
2001 aModifierFlags,
2002 responder.GetObserver());
2004 return IPC_OK();
2007 mozilla::ipc::IPCResult BrowserParent::RecvLockNativePointer() {
2008 if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
2009 mLockedNativePointer = true; // do before updating the center
2010 UpdateNativePointerLockCenter(widget);
2011 widget->LockNativePointer();
2013 return IPC_OK();
2016 void BrowserParent::UnlockNativePointer() {
2017 if (!mLockedNativePointer) {
2018 return;
2020 if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
2021 widget->UnlockNativePointer();
2022 mLockedNativePointer = false;
2026 mozilla::ipc::IPCResult BrowserParent::RecvUnlockNativePointer() {
2027 UnlockNativePointer();
2028 return IPC_OK();
2031 void BrowserParent::SendRealKeyEvent(WidgetKeyboardEvent& aEvent) {
2032 if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
2033 return;
2035 aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
2037 // NOTE: If you call `InitAllEditCommands()` for the other messages too,
2038 // you also need to update
2039 // TextEventDispatcher::DispatchKeyboardEventInternal().
2040 if (aEvent.mMessage == eKeyPress) {
2041 // If current input context is editable, the edit commands are initialized
2042 // by TextEventDispatcher::DispatchKeyboardEventInternal(). Otherwise,
2043 // we need to do it here (they are not necessary for the parent process,
2044 // therefore, we need to do it here for saving the runtime cost).
2045 if (!aEvent.AreAllEditCommandsInitialized()) {
2046 // XXX Is it good thing that the keypress event will be handled in an
2047 // editor even though the user pressed the key combination before the
2048 // focus change has not been completed in the parent process yet or
2049 // focus change will happen? If no, we can stop doing this.
2050 Maybe<WritingMode> writingMode;
2051 if (aEvent.mWidget) {
2052 if (RefPtr<widget::TextEventDispatcher> dispatcher =
2053 aEvent.mWidget->GetTextEventDispatcher()) {
2054 writingMode = dispatcher->MaybeQueryWritingModeAtSelection();
2057 aEvent.InitAllEditCommands(writingMode);
2059 } else {
2060 aEvent.PreventNativeKeyBindings();
2062 SentKeyEventData sendKeyEventData{
2063 aEvent.mKeyCode, aEvent.mCharCode, aEvent.mPseudoCharCode,
2064 aEvent.mKeyNameIndex, aEvent.mCodeNameIndex, aEvent.mModifiers,
2065 nsID::GenerateUUID()};
2066 const bool ok =
2067 Manager()->IsInputPriorityEventEnabled()
2068 ? PBrowserParent::SendRealKeyEvent(aEvent, sendKeyEventData.mUUID)
2069 : PBrowserParent::SendNormalPriorityRealKeyEvent(
2070 aEvent, sendKeyEventData.mUUID);
2072 NS_WARNING_ASSERTION(ok, "PBrowserParent::SendRealKeyEvent() failed");
2073 MOZ_ASSERT(!ok || aEvent.HasBeenPostedToRemoteProcess());
2074 if (ok && aEvent.IsWaitingReplyFromRemoteProcess()) {
2075 mWaitingReplyKeyboardEvents.AppendElement(sendKeyEventData);
2079 void BrowserParent::SendRealTouchEvent(WidgetTouchEvent& aEvent) {
2080 if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
2081 return;
2084 // PresShell::HandleEventInternal adds touches on touch end/cancel. This
2085 // confuses remote content and the panning and zooming logic into thinking
2086 // that the added touches are part of the touchend/cancel, when actually
2087 // they're not.
2088 if (aEvent.mMessage == eTouchEnd || aEvent.mMessage == eTouchCancel) {
2089 aEvent.mTouches.RemoveElementsBy(
2090 [](const auto& touch) { return !touch->mChanged; });
2093 APZData apzData;
2094 ApzAwareEventRoutingToChild(&apzData.guid, &apzData.blockId,
2095 &apzData.apzResponse);
2097 if (mIsDestroyed) {
2098 return;
2101 for (uint32_t i = 0; i < aEvent.mTouches.Length(); i++) {
2102 aEvent.mTouches[i]->mRefPoint =
2103 TransformParentToChild(aEvent.mTouches[i]->mRefPoint);
2106 static uint32_t sConsecutiveTouchMoveCount = 0;
2107 if (aEvent.mMessage == eTouchMove) {
2108 ++sConsecutiveTouchMoveCount;
2109 SendRealTouchMoveEvent(aEvent, apzData, sConsecutiveTouchMoveCount);
2110 return;
2113 sConsecutiveTouchMoveCount = 0;
2114 DebugOnly<bool> ret =
2115 Manager()->IsInputPriorityEventEnabled()
2116 ? PBrowserParent::SendRealTouchEvent(
2117 aEvent, apzData.guid, apzData.blockId, apzData.apzResponse)
2118 : PBrowserParent::SendNormalPriorityRealTouchEvent(
2119 aEvent, apzData.guid, apzData.blockId, apzData.apzResponse);
2121 NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealTouchEvent() failed");
2122 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
2125 void BrowserParent::SendRealTouchMoveEvent(
2126 WidgetTouchEvent& aEvent, APZData& aAPZData,
2127 uint32_t aConsecutiveTouchMoveCount) {
2128 // Touchmove handling is complicated, since IPC compression should be used
2129 // only when there are consecutive touch objects for the same touch on the
2130 // same BrowserParent. IPC compression can be disabled by switching to
2131 // different IPC message.
2132 static bool sIPCMessageType1 = true;
2133 static TabId sLastTargetBrowserParent(0);
2134 static Maybe<APZData> sPreviousAPZData;
2135 // Artificially limit max touch points to 10. That should be in practise
2136 // more than enough.
2137 const uint32_t kMaxTouchMoveIdentifiers = 10;
2138 static Maybe<int32_t> sLastTouchMoveIdentifiers[kMaxTouchMoveIdentifiers];
2140 // Returns true if aIdentifiers contains all the touches in
2141 // sLastTouchMoveIdentifiers.
2142 auto LastTouchMoveIdentifiersContainedIn =
2143 [&](const nsTArray<int32_t>& aIdentifiers) -> bool {
2144 for (Maybe<int32_t>& entry : sLastTouchMoveIdentifiers) {
2145 if (entry.isSome() && !aIdentifiers.Contains(entry.value())) {
2146 return false;
2149 return true;
2152 // Cache touch identifiers in sLastTouchMoveIdentifiers array to be used
2153 // when checking whether compression can be done for the next touchmove.
2154 auto SetLastTouchMoveIdentifiers =
2155 [&](const nsTArray<int32_t>& aIdentifiers) {
2156 for (Maybe<int32_t>& entry : sLastTouchMoveIdentifiers) {
2157 entry.reset();
2160 MOZ_ASSERT(aIdentifiers.Length() <= kMaxTouchMoveIdentifiers);
2161 for (uint32_t j = 0; j < aIdentifiers.Length(); ++j) {
2162 sLastTouchMoveIdentifiers[j].emplace(aIdentifiers[j]);
2166 AutoTArray<int32_t, kMaxTouchMoveIdentifiers> changedTouches;
2167 bool preventCompression = !StaticPrefs::dom_events_compress_touchmove() ||
2168 // Ensure the very first touchmove isn't overridden
2169 // by the second one, so that web pages can get
2170 // accurate coordinates for the first touchmove.
2171 aConsecutiveTouchMoveCount < 3 ||
2172 sPreviousAPZData.isNothing() ||
2173 sPreviousAPZData.value() != aAPZData ||
2174 sLastTargetBrowserParent != GetTabId() ||
2175 aEvent.mTouches.Length() > kMaxTouchMoveIdentifiers;
2177 if (!preventCompression) {
2178 for (RefPtr<Touch>& touch : aEvent.mTouches) {
2179 if (touch->mChanged) {
2180 changedTouches.AppendElement(touch->mIdentifier);
2184 // Prevent compression if the new event has fewer or different touches
2185 // than the old one.
2186 preventCompression = !LastTouchMoveIdentifiersContainedIn(changedTouches);
2189 if (preventCompression) {
2190 sIPCMessageType1 = !sIPCMessageType1;
2193 // Update the last touch move identifiers always, so that when the next
2194 // event comes in, the new identifiers can be compared to the old ones.
2195 // If the pref is disabled, this just does a quick small loop.
2196 SetLastTouchMoveIdentifiers(changedTouches);
2197 sPreviousAPZData.reset();
2198 sPreviousAPZData.emplace(aAPZData);
2199 sLastTargetBrowserParent = GetTabId();
2201 DebugOnly<bool> ret = true;
2202 if (sIPCMessageType1) {
2203 ret =
2204 Manager()->IsInputPriorityEventEnabled()
2205 ? PBrowserParent::SendRealTouchMoveEvent(
2206 aEvent, aAPZData.guid, aAPZData.blockId, aAPZData.apzResponse)
2207 : PBrowserParent::SendNormalPriorityRealTouchMoveEvent(
2208 aEvent, aAPZData.guid, aAPZData.blockId,
2209 aAPZData.apzResponse);
2210 } else {
2211 ret =
2212 Manager()->IsInputPriorityEventEnabled()
2213 ? PBrowserParent::SendRealTouchMoveEvent2(
2214 aEvent, aAPZData.guid, aAPZData.blockId, aAPZData.apzResponse)
2215 : PBrowserParent::SendNormalPriorityRealTouchMoveEvent2(
2216 aEvent, aAPZData.guid, aAPZData.blockId,
2217 aAPZData.apzResponse);
2220 NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealTouchMoveEvent() failed");
2221 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
2224 bool BrowserParent::SendHandleTap(TapType aType,
2225 const LayoutDevicePoint& aPoint,
2226 Modifiers aModifiers,
2227 const ScrollableLayerGuid& aGuid,
2228 uint64_t aInputBlockId) {
2229 if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
2230 return false;
2232 if ((aType == TapType::eSingleTap || aType == TapType::eSecondTap)) {
2233 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
2234 if (RefPtr<nsFrameLoader> frameLoader = GetFrameLoader()) {
2235 if (RefPtr<Element> element = frameLoader->GetOwnerContent()) {
2236 fm->SetFocus(element, nsIFocusManager::FLAG_BYMOUSE |
2237 nsIFocusManager::FLAG_BYTOUCH |
2238 nsIFocusManager::FLAG_NOSCROLL);
2243 return Manager()->IsInputPriorityEventEnabled()
2244 ? PBrowserParent::SendHandleTap(aType,
2245 TransformParentToChild(aPoint),
2246 aModifiers, aGuid, aInputBlockId)
2247 : PBrowserParent::SendNormalPriorityHandleTap(
2248 aType, TransformParentToChild(aPoint), aModifiers, aGuid,
2249 aInputBlockId);
2252 mozilla::ipc::IPCResult BrowserParent::RecvSyncMessage(
2253 const nsString& aMessage, const ClonedMessageData& aData,
2254 nsTArray<StructuredCloneData>* aRetVal) {
2255 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("BrowserParent::RecvSyncMessage",
2256 OTHER, aMessage);
2257 MMPrinter::Print("BrowserParent::RecvSyncMessage", aMessage, aData);
2259 StructuredCloneData data;
2260 ipc::UnpackClonedMessageData(aData, data);
2262 if (!ReceiveMessage(aMessage, true, &data, aRetVal)) {
2263 return IPC_FAIL_NO_REASON(this);
2265 return IPC_OK();
2268 mozilla::ipc::IPCResult BrowserParent::RecvAsyncMessage(
2269 const nsString& aMessage, const ClonedMessageData& aData) {
2270 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("BrowserParent::RecvAsyncMessage",
2271 OTHER, aMessage);
2272 MMPrinter::Print("BrowserParent::RecvAsyncMessage", aMessage, aData);
2274 StructuredCloneData data;
2275 ipc::UnpackClonedMessageData(aData, data);
2277 if (!ReceiveMessage(aMessage, false, &data, nullptr)) {
2278 return IPC_FAIL_NO_REASON(this);
2280 return IPC_OK();
2283 mozilla::ipc::IPCResult BrowserParent::RecvSetCursor(
2284 const nsCursor& aCursor, const bool& aHasCustomCursor,
2285 Maybe<BigBuffer>&& aCursorData, const uint32_t& aWidth,
2286 const uint32_t& aHeight, const float& aResolutionX,
2287 const float& aResolutionY, const uint32_t& aStride,
2288 const gfx::SurfaceFormat& aFormat, const uint32_t& aHotspotX,
2289 const uint32_t& aHotspotY, const bool& aForce) {
2290 nsCOMPtr<nsIWidget> widget = GetWidget();
2291 if (!widget) {
2292 return IPC_OK();
2295 if (aForce) {
2296 widget->ClearCachedCursor();
2299 nsCOMPtr<imgIContainer> cursorImage;
2300 if (aHasCustomCursor) {
2301 const bool cursorDataValid = [&] {
2302 if (!aCursorData) {
2303 return false;
2305 auto expectedSize = CheckedInt<uint32_t>(aHeight) * aStride;
2306 if (!expectedSize.isValid() ||
2307 expectedSize.value() != aCursorData->Size()) {
2308 return false;
2310 auto minStride =
2311 CheckedInt<uint32_t>(aWidth) * gfx::BytesPerPixel(aFormat);
2312 if (!minStride.isValid() || aStride < minStride.value()) {
2313 return false;
2315 return true;
2316 }();
2317 if (!cursorDataValid) {
2318 return IPC_FAIL(this, "Invalid custom cursor data");
2320 const gfx::IntSize size(aWidth, aHeight);
2321 RefPtr<gfx::DataSourceSurface> customCursor =
2322 gfx::CreateDataSourceSurfaceFromData(size, aFormat, aCursorData->Data(),
2323 aStride);
2325 RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(customCursor, size);
2326 cursorImage = image::ImageOps::CreateFromDrawable(drawable);
2329 mCursor = nsIWidget::Cursor{aCursor,
2330 std::move(cursorImage),
2331 aHotspotX,
2332 aHotspotY,
2333 {aResolutionX, aResolutionY}};
2334 if (!mRemoteTargetSetsCursor) {
2335 return IPC_OK();
2338 widget->SetCursor(mCursor);
2339 return IPC_OK();
2342 mozilla::ipc::IPCResult BrowserParent::RecvSetLinkStatus(
2343 const nsString& aStatus) {
2344 nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow = GetXULBrowserWindow();
2345 if (!xulBrowserWindow) {
2346 return IPC_OK();
2349 xulBrowserWindow->SetOverLink(aStatus);
2351 return IPC_OK();
2354 mozilla::ipc::IPCResult BrowserParent::RecvShowTooltip(
2355 const uint32_t& aX, const uint32_t& aY, const nsString& aTooltip,
2356 const nsString& aDirection) {
2357 nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow = GetXULBrowserWindow();
2358 if (!xulBrowserWindow) {
2359 return IPC_OK();
2362 // ShowTooltip will end up accessing XULElement properties in JS (specifically
2363 // BoxObject). However, to get it to JS, we need to make sure we're a
2364 // nsFrameLoaderOwner, which implies we're a XULFrameElement. We can then
2365 // safely pass Element into JS.
2366 RefPtr<nsFrameLoaderOwner> flo = do_QueryObject(mFrameElement);
2367 if (!flo) return IPC_OK();
2369 nsCOMPtr<Element> el = do_QueryInterface(flo);
2370 if (!el) return IPC_OK();
2372 if (NS_SUCCEEDED(
2373 xulBrowserWindow->ShowTooltip(aX, aY, aTooltip, aDirection, el))) {
2374 mShowingTooltip = true;
2376 return IPC_OK();
2379 mozilla::ipc::IPCResult BrowserParent::RecvHideTooltip() {
2380 mShowingTooltip = false;
2382 nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow = GetXULBrowserWindow();
2383 if (!xulBrowserWindow) {
2384 return IPC_OK();
2387 xulBrowserWindow->HideTooltip();
2388 return IPC_OK();
2391 mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMEFocus(
2392 const ContentCache& aContentCache, const IMENotification& aIMENotification,
2393 NotifyIMEFocusResolver&& aResolve) {
2394 if (mIsDestroyed) {
2395 return IPC_OK();
2398 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2399 if (!widget) {
2400 aResolve(IMENotificationRequests());
2401 return IPC_OK();
2403 if (NS_WARN_IF(!aContentCache.IsValid())) {
2404 return IPC_FAIL(this, "Invalid content cache data");
2406 mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
2407 IMEStateManager::NotifyIME(aIMENotification, widget, this);
2409 IMENotificationRequests requests;
2410 if (aIMENotification.mMessage == NOTIFY_IME_OF_FOCUS) {
2411 requests = widget->IMENotificationRequestsRef();
2413 aResolve(requests);
2415 return IPC_OK();
2418 mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMETextChange(
2419 const ContentCache& aContentCache,
2420 const IMENotification& aIMENotification) {
2421 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2422 if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
2423 return IPC_OK();
2425 if (NS_WARN_IF(!aContentCache.IsValid())) {
2426 return IPC_FAIL(this, "Invalid content cache data");
2428 mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
2429 mContentCache.MaybeNotifyIME(widget, aIMENotification);
2430 return IPC_OK();
2433 mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMECompositionUpdate(
2434 const ContentCache& aContentCache,
2435 const IMENotification& aIMENotification) {
2436 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2437 if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
2438 return IPC_OK();
2440 if (NS_WARN_IF(!aContentCache.IsValid())) {
2441 return IPC_FAIL(this, "Invalid content cache data");
2443 mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
2444 mContentCache.MaybeNotifyIME(widget, aIMENotification);
2445 return IPC_OK();
2448 mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMESelection(
2449 const ContentCache& aContentCache,
2450 const IMENotification& aIMENotification) {
2451 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2452 if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
2453 return IPC_OK();
2455 if (NS_WARN_IF(!aContentCache.IsValid())) {
2456 return IPC_FAIL(this, "Invalid content cache data");
2458 mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
2459 mContentCache.MaybeNotifyIME(widget, aIMENotification);
2460 return IPC_OK();
2463 mozilla::ipc::IPCResult BrowserParent::RecvUpdateContentCache(
2464 const ContentCache& aContentCache) {
2465 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2466 if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
2467 return IPC_OK();
2469 if (NS_WARN_IF(!aContentCache.IsValid())) {
2470 return IPC_FAIL(this, "Invalid content cache data");
2472 mContentCache.AssignContent(aContentCache, widget);
2473 return IPC_OK();
2476 mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMEMouseButtonEvent(
2477 const IMENotification& aIMENotification, bool* aConsumedByIME) {
2478 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2479 if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
2480 *aConsumedByIME = false;
2481 return IPC_OK();
2483 nsresult rv = IMEStateManager::NotifyIME(aIMENotification, widget, this);
2484 *aConsumedByIME = rv == NS_SUCCESS_EVENT_CONSUMED;
2485 return IPC_OK();
2488 mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMEPositionChange(
2489 const ContentCache& aContentCache,
2490 const IMENotification& aIMENotification) {
2491 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2492 if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
2493 return IPC_OK();
2495 if (NS_WARN_IF(!aContentCache.IsValid())) {
2496 return IPC_FAIL(this, "Invalid content cache data");
2498 mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
2499 mContentCache.MaybeNotifyIME(widget, aIMENotification);
2500 return IPC_OK();
2503 mozilla::ipc::IPCResult BrowserParent::RecvOnEventNeedingAckHandled(
2504 const EventMessage& aMessage, const uint32_t& aCompositionId) {
2505 // This is called when the child process receives WidgetCompositionEvent or
2506 // WidgetSelectionEvent.
2507 // FYI: Don't check if widget is nullptr here because it's more important to
2508 // notify mContentCahce of this than handling something in it.
2509 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2511 // While calling OnEventNeedingAckHandled(), BrowserParent *might* be
2512 // destroyed since it may send notifications to IME.
2513 RefPtr<BrowserParent> kungFuDeathGrip(this);
2514 mContentCache.OnEventNeedingAckHandled(widget, aMessage, aCompositionId);
2515 return IPC_OK();
2518 mozilla::ipc::IPCResult BrowserParent::RecvRequestFocus(
2519 const bool& aCanRaise, const CallerType aCallerType) {
2520 LOGBROWSERFOCUS(("RecvRequestFocus %p, aCanRaise: %d", this, aCanRaise));
2521 if (BrowserBridgeParent* bridgeParent = GetBrowserBridgeParent()) {
2522 mozilla::Unused << bridgeParent->SendRequestFocus(aCanRaise, aCallerType);
2523 return IPC_OK();
2526 if (!mFrameElement) {
2527 return IPC_OK();
2530 nsContentUtils::RequestFrameFocus(*mFrameElement, aCanRaise, aCallerType);
2531 return IPC_OK();
2534 mozilla::ipc::IPCResult BrowserParent::RecvWheelZoomChange(bool aIncrease) {
2535 RefPtr<BrowsingContext> bc = GetBrowsingContext();
2536 if (!bc) {
2537 return IPC_OK();
2540 bc->Canonical()->DispatchWheelZoomChange(aIncrease);
2541 return IPC_OK();
2544 mozilla::ipc::IPCResult BrowserParent::RecvEnableDisableCommands(
2545 const MaybeDiscarded<BrowsingContext>& aContext, const nsString& aAction,
2546 nsTArray<nsCString>&& aEnabledCommands,
2547 nsTArray<nsCString>&& aDisabledCommands) {
2548 if (aContext.IsNullOrDiscarded()) {
2549 return IPC_OK();
2552 nsCOMPtr<nsIBrowserController> browserController = do_QueryActor(
2553 "Controllers", aContext.get_canonical()->GetCurrentWindowGlobal());
2554 if (browserController) {
2555 browserController->EnableDisableCommands(aAction, aEnabledCommands,
2556 aDisabledCommands);
2559 return IPC_OK();
2562 LayoutDeviceIntPoint BrowserParent::TransformPoint(
2563 const LayoutDeviceIntPoint& aPoint,
2564 const LayoutDeviceToLayoutDeviceMatrix4x4& aMatrix) {
2565 LayoutDevicePoint floatPoint(aPoint);
2566 LayoutDevicePoint floatTransformed = TransformPoint(floatPoint, aMatrix);
2567 // The next line loses precision if an out-of-process iframe
2568 // has been scaled or rotated.
2569 return RoundedToInt(floatTransformed);
2572 LayoutDevicePoint BrowserParent::TransformPoint(
2573 const LayoutDevicePoint& aPoint,
2574 const LayoutDeviceToLayoutDeviceMatrix4x4& aMatrix) {
2575 return aMatrix.TransformPoint(aPoint);
2578 LayoutDeviceIntPoint BrowserParent::TransformParentToChild(
2579 const LayoutDeviceIntPoint& aPoint) {
2580 LayoutDeviceToLayoutDeviceMatrix4x4 matrix =
2581 GetChildToParentConversionMatrix();
2582 if (!matrix.Invert()) {
2583 return LayoutDeviceIntPoint();
2585 auto transformed = UntransformBy(matrix, aPoint);
2586 if (!transformed) {
2587 return LayoutDeviceIntPoint();
2589 return transformed.ref();
2592 LayoutDevicePoint BrowserParent::TransformParentToChild(
2593 const LayoutDevicePoint& aPoint) {
2594 LayoutDeviceToLayoutDeviceMatrix4x4 matrix =
2595 GetChildToParentConversionMatrix();
2596 if (!matrix.Invert()) {
2597 return LayoutDevicePoint();
2599 auto transformed = UntransformBy(matrix, aPoint);
2600 if (!transformed) {
2601 return LayoutDeviceIntPoint();
2603 return transformed.ref();
2606 LayoutDeviceIntPoint BrowserParent::TransformChildToParent(
2607 const LayoutDeviceIntPoint& aPoint) {
2608 return TransformPoint(aPoint, GetChildToParentConversionMatrix());
2611 LayoutDevicePoint BrowserParent::TransformChildToParent(
2612 const LayoutDevicePoint& aPoint) {
2613 return TransformPoint(aPoint, GetChildToParentConversionMatrix());
2616 LayoutDeviceIntRect BrowserParent::TransformChildToParent(
2617 const LayoutDeviceIntRect& aRect) {
2618 LayoutDeviceToLayoutDeviceMatrix4x4 matrix =
2619 GetChildToParentConversionMatrix();
2620 LayoutDeviceRect floatRect(aRect);
2621 // The outcome is not ideal if an out-of-process iframe has been rotated
2622 LayoutDeviceRect floatTransformed = matrix.TransformBounds(floatRect);
2623 // The next line loses precision if an out-of-process iframe
2624 // has been scaled or rotated.
2625 return RoundedToInt(floatTransformed);
2628 LayoutDeviceToLayoutDeviceMatrix4x4
2629 BrowserParent::GetChildToParentConversionMatrix() {
2630 if (mChildToParentConversionMatrix) {
2631 return *mChildToParentConversionMatrix;
2633 LayoutDevicePoint offset(-GetChildProcessOffset());
2634 return LayoutDeviceToLayoutDeviceMatrix4x4::Translation(offset);
2637 void BrowserParent::SetChildToParentConversionMatrix(
2638 const Maybe<LayoutDeviceToLayoutDeviceMatrix4x4>& aMatrix,
2639 const ScreenRect& aRemoteDocumentRect) {
2640 if (mChildToParentConversionMatrix == aMatrix &&
2641 mRemoteDocumentRect.isSome() &&
2642 mRemoteDocumentRect.value() == aRemoteDocumentRect) {
2643 return;
2646 mChildToParentConversionMatrix = aMatrix;
2647 mRemoteDocumentRect = Some(aRemoteDocumentRect);
2648 if (mIsDestroyed) {
2649 return;
2651 mozilla::Unused << SendChildToParentMatrix(ToUnknownMatrix(aMatrix),
2652 aRemoteDocumentRect);
2655 LayoutDeviceIntPoint BrowserParent::GetChildProcessOffset() {
2656 // The "toplevel widget" in child processes is always at position
2657 // 0,0. Map the event coordinates to match that.
2659 LayoutDeviceIntPoint offset(0, 0);
2660 RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
2661 if (!frameLoader) {
2662 return offset;
2664 nsIFrame* targetFrame = frameLoader->GetPrimaryFrameOfOwningContent();
2665 if (!targetFrame) {
2666 return offset;
2669 nsCOMPtr<nsIWidget> widget = GetWidget();
2670 if (!widget) {
2671 return offset;
2674 nsPresContext* presContext = targetFrame->PresContext();
2675 nsIFrame* rootFrame = presContext->PresShell()->GetRootFrame();
2676 nsView* rootView = rootFrame ? rootFrame->GetView() : nullptr;
2677 if (!rootView) {
2678 return offset;
2681 // Note that we don't want to take into account transforms here:
2682 #if 0
2683 nsPoint pt(0, 0);
2684 nsLayoutUtils::TransformPoint(targetFrame, rootFrame, pt);
2685 #endif
2686 // In practice, when transforms are applied to this frameLoader, we currently
2687 // get the wrong results whether we take transforms into account here or not.
2688 // But applying transforms here gives us the wrong results in all
2689 // circumstances when transforms are applied, unless they're purely
2690 // translational. It also gives us the wrong results whenever CSS transitions
2691 // are used to apply transforms, since the offeets aren't updated as the
2692 // transition is animated.
2694 // What we actually need to do is apply the transforms to the coordinates of
2695 // any events we send to the child, and reverse them for any screen
2696 // coordinates that we retrieve from the child.
2698 // TODO: Once we take into account transforms here, set viewportType
2699 // correctly. For now we use Visual as this means we don't apply
2700 // the layout-to-visual transform in TranslateViewToWidget().
2701 ViewportType viewportType = ViewportType::Visual;
2703 nsPoint pt = targetFrame->GetOffsetTo(rootFrame);
2704 return -nsLayoutUtils::TranslateViewToWidget(presContext, rootView, pt,
2705 viewportType, widget);
2708 LayoutDeviceIntPoint BrowserParent::GetClientOffset() {
2709 nsCOMPtr<nsIWidget> widget = GetWidget();
2710 nsCOMPtr<nsIWidget> docWidget = GetDocWidget();
2712 if (widget == docWidget) {
2713 return widget->GetClientOffset();
2716 return (docWidget->GetClientOffset() +
2717 nsLayoutUtils::WidgetToWidgetOffset(widget, docWidget));
2720 void BrowserParent::StopIMEStateManagement() {
2721 if (mIsDestroyed) {
2722 return;
2724 Unused << SendStopIMEStateManagement();
2727 mozilla::ipc::IPCResult BrowserParent::RecvReplyKeyEvent(
2728 const WidgetKeyboardEvent& aEvent, const nsID& aUUID) {
2729 NS_ENSURE_TRUE(mFrameElement, IPC_OK());
2731 // First, verify aEvent is what we've sent to a remote process.
2732 Maybe<size_t> index = [&]() -> Maybe<size_t> {
2733 for (const size_t i : IntegerRange(mWaitingReplyKeyboardEvents.Length())) {
2734 const SentKeyEventData& data = mWaitingReplyKeyboardEvents[i];
2735 if (data.mUUID.Equals(aUUID)) {
2736 if (NS_WARN_IF(data.mKeyCode != aEvent.mKeyCode) ||
2737 NS_WARN_IF(data.mCharCode != aEvent.mCharCode) ||
2738 NS_WARN_IF(data.mPseudoCharCode != aEvent.mPseudoCharCode) ||
2739 NS_WARN_IF(data.mKeyNameIndex != aEvent.mKeyNameIndex) ||
2740 NS_WARN_IF(data.mCodeNameIndex != aEvent.mCodeNameIndex) ||
2741 NS_WARN_IF(data.mModifiers != aEvent.mModifiers)) {
2742 // Got different event data from what we stored before dispatching an
2743 // event with the ID.
2744 return Nothing();
2746 return Some(i);
2749 // No entry found.
2750 return Nothing();
2751 }();
2752 if (MOZ_UNLIKELY(index.isNothing())) {
2753 return IPC_FAIL(this, "Bogus reply keyboard event");
2755 // Don't discard the older keyboard events because the order may be changed if
2756 // the remote process has a event listener which takes too long time and while
2757 // the freezing, user may switch the tab, or if the remote process sends
2758 // synchronous XMLHttpRequest.
2759 mWaitingReplyKeyboardEvents.RemoveElementAt(*index);
2761 // If the event propagation was stopped by the child, it means that the event
2762 // was ignored in the child. In the case, we should ignore it too because the
2763 // focused web app didn't have a chance to prevent its default.
2764 if (aEvent.PropagationStopped()) {
2765 return IPC_OK();
2768 WidgetKeyboardEvent localEvent(aEvent);
2769 localEvent.MarkAsHandledInRemoteProcess();
2771 // Here we convert the WidgetEvent that we received to an Event
2772 // to be able to dispatch it to the <browser> element as the target element.
2773 RefPtr<nsPresContext> presContext =
2774 mFrameElement->OwnerDoc()->GetPresContext();
2775 NS_ENSURE_TRUE(presContext, IPC_OK());
2777 AutoHandlingUserInputStatePusher userInpStatePusher(localEvent.IsTrusted(),
2778 &localEvent);
2780 nsEventStatus status = nsEventStatus_eIgnore;
2782 // Handle access key in this process before dispatching reply event because
2783 // ESM handles it before dispatching the event to the DOM tree.
2784 if (localEvent.mMessage == eKeyPress &&
2785 (localEvent.ModifiersMatchWithAccessKey(AccessKeyType::eChrome) ||
2786 localEvent.ModifiersMatchWithAccessKey(AccessKeyType::eContent))) {
2787 RefPtr<EventStateManager> esm = presContext->EventStateManager();
2788 AutoTArray<uint32_t, 10> accessCharCodes;
2789 localEvent.GetAccessKeyCandidates(accessCharCodes);
2790 if (esm->HandleAccessKey(&localEvent, presContext, accessCharCodes)) {
2791 status = nsEventStatus_eConsumeNoDefault;
2795 RefPtr<Element> frameElement = mFrameElement;
2796 EventDispatcher::Dispatch(frameElement, presContext, &localEvent, nullptr,
2797 &status);
2799 if (!localEvent.DefaultPrevented() &&
2800 !localEvent.mFlags.mIsSynthesizedForTests) {
2801 nsCOMPtr<nsIWidget> widget = GetWidget();
2802 if (widget) {
2803 widget->PostHandleKeyEvent(&localEvent);
2804 localEvent.StopPropagation();
2808 return IPC_OK();
2811 mozilla::ipc::IPCResult BrowserParent::RecvAccessKeyNotHandled(
2812 const WidgetKeyboardEvent& aEvent) {
2813 NS_ENSURE_TRUE(mFrameElement, IPC_OK());
2815 // This is called only when this process had focus and HandleAccessKey
2816 // message was posted to all remote process and each remote process didn't
2817 // execute any content access keys.
2819 if (MOZ_UNLIKELY(aEvent.mMessage != eKeyPress || !aEvent.IsTrusted())) {
2820 return IPC_FAIL(this, "Called with unexpected event");
2823 // If there is no requesting event, the event may have already been handled
2824 // when it's returned from another remote process.
2825 if (MOZ_UNLIKELY(!RequestingAccessKeyEventData::IsSet())) {
2826 return IPC_OK();
2829 // If the event does not match with the one which we requested a remote
2830 // process to handle access key of (that means that we has already requested
2831 // for another key press), we should ignore this call because user focuses
2832 // to the last key press.
2833 if (MOZ_UNLIKELY(!RequestingAccessKeyEventData::Equals(aEvent))) {
2834 return IPC_OK();
2837 RequestingAccessKeyEventData::Clear();
2839 WidgetKeyboardEvent localEvent(aEvent);
2840 localEvent.MarkAsHandledInRemoteProcess();
2841 localEvent.mMessage = eAccessKeyNotFound;
2843 // Here we convert the WidgetEvent that we received to an Event
2844 // to be able to dispatch it to the <browser> element as the target element.
2845 Document* doc = mFrameElement->OwnerDoc();
2846 PresShell* presShell = doc->GetPresShell();
2847 NS_ENSURE_TRUE(presShell, IPC_OK());
2849 if (presShell->CanDispatchEvent()) {
2850 RefPtr<nsPresContext> presContext = presShell->GetPresContext();
2851 NS_ENSURE_TRUE(presContext, IPC_OK());
2853 RefPtr<Element> frameElement = mFrameElement;
2854 EventDispatcher::Dispatch(frameElement, presContext, &localEvent);
2857 return IPC_OK();
2860 mozilla::ipc::IPCResult BrowserParent::RecvRegisterProtocolHandler(
2861 const nsString& aScheme, nsIURI* aHandlerURI, const nsString& aTitle,
2862 nsIURI* aDocURI) {
2863 nsCOMPtr<nsIWebProtocolHandlerRegistrar> registrar =
2864 do_GetService(NS_WEBPROTOCOLHANDLERREGISTRAR_CONTRACTID);
2865 if (registrar) {
2866 registrar->RegisterProtocolHandler(aScheme, aHandlerURI, aTitle, aDocURI,
2867 mFrameElement);
2870 return IPC_OK();
2873 mozilla::ipc::IPCResult BrowserParent::RecvOnStateChange(
2874 const WebProgressData& aWebProgressData, const RequestData& aRequestData,
2875 const uint32_t aStateFlags, const nsresult aStatus,
2876 const Maybe<WebProgressStateChangeData>& aStateChangeData) {
2877 RefPtr<CanonicalBrowsingContext> browsingContext =
2878 BrowsingContextForWebProgress(aWebProgressData);
2879 if (!browsingContext) {
2880 return IPC_OK();
2883 nsCOMPtr<nsIRequest> request;
2884 if (aRequestData.requestURI()) {
2885 request = MakeAndAddRef<RemoteWebProgressRequest>(
2886 aRequestData.requestURI(), aRequestData.originalRequestURI(),
2887 aRequestData.matchedList());
2890 if (aStateChangeData.isSome()) {
2891 if (!browsingContext->IsTopContent()) {
2892 return IPC_FAIL(
2893 this,
2894 "Unexpected WebProgressStateChangeData for non toplevel webProgress");
2897 if (nsCOMPtr<nsIBrowser> browser = GetBrowser()) {
2898 Unused << browser->SetIsNavigating(aStateChangeData->isNavigating());
2899 Unused << browser->SetMayEnableCharacterEncodingMenu(
2900 aStateChangeData->mayEnableCharacterEncodingMenu());
2901 Unused << browser->UpdateForStateChange(aStateChangeData->charset(),
2902 aStateChangeData->documentURI(),
2903 aStateChangeData->contentType());
2907 if (auto* listener = browsingContext->GetWebProgress()) {
2908 listener->OnStateChange(listener, request, aStateFlags, aStatus);
2911 return IPC_OK();
2914 mozilla::ipc::IPCResult BrowserParent::RecvOnProgressChange(
2915 const int32_t aCurTotalProgress, const int32_t aMaxTotalProgress) {
2916 // We only collect progress change notifications for the toplevel
2917 // BrowserParent.
2918 // FIXME: In the future, consider merging in progress change information from
2919 // oop subframes.
2920 if (!GetBrowsingContext()->IsTopContent() ||
2921 !GetBrowsingContext()->GetWebProgress()) {
2922 return IPC_OK();
2925 GetBrowsingContext()->GetWebProgress()->OnProgressChange(
2926 nullptr, nullptr, 0, 0, aCurTotalProgress, aMaxTotalProgress);
2928 return IPC_OK();
2931 mozilla::ipc::IPCResult BrowserParent::RecvOnLocationChange(
2932 const WebProgressData& aWebProgressData, const RequestData& aRequestData,
2933 nsIURI* aLocation, const uint32_t aFlags, const bool aCanGoBack,
2934 const bool aCanGoForward,
2935 const Maybe<WebProgressLocationChangeData>& aLocationChangeData) {
2936 RefPtr<CanonicalBrowsingContext> browsingContext =
2937 BrowsingContextForWebProgress(aWebProgressData);
2938 if (!browsingContext) {
2939 return IPC_OK();
2942 nsCOMPtr<nsIRequest> request;
2943 if (aRequestData.requestURI()) {
2944 request = MakeAndAddRef<RemoteWebProgressRequest>(
2945 aRequestData.requestURI(), aRequestData.originalRequestURI(),
2946 aRequestData.matchedList());
2949 browsingContext->SetCurrentRemoteURI(aLocation);
2951 nsCOMPtr<nsIBrowser> browser = GetBrowser();
2952 if (!mozilla::SessionHistoryInParent() && browser) {
2953 Unused << browser->UpdateWebNavigationForLocationChange(aCanGoBack,
2954 aCanGoForward);
2957 if (aLocationChangeData.isSome()) {
2958 if (!browsingContext->IsTopContent()) {
2959 return IPC_FAIL(this,
2960 "Unexpected WebProgressLocationChangeData for non "
2961 "toplevel webProgress");
2964 if (browser) {
2965 Unused << browser->SetIsNavigating(aLocationChangeData->isNavigating());
2966 Unused << browser->UpdateForLocationChange(
2967 aLocation, aLocationChangeData->charset(),
2968 aLocationChangeData->mayEnableCharacterEncodingMenu(),
2969 aLocationChangeData->documentURI(), aLocationChangeData->title(),
2970 aLocationChangeData->contentPrincipal(),
2971 aLocationChangeData->contentPartitionedPrincipal(),
2972 aLocationChangeData->csp(), aLocationChangeData->referrerInfo(),
2973 aLocationChangeData->isSyntheticDocument(),
2974 aLocationChangeData->requestContextID().isSome(),
2975 aLocationChangeData->requestContextID().valueOr(0),
2976 aLocationChangeData->contentType());
2980 if (auto* listener = browsingContext->GetWebProgress()) {
2981 listener->OnLocationChange(listener, request, aLocation, aFlags);
2984 // Since we've now changed Documents, notify the BrowsingContext that we've
2985 // changed. Ideally we'd just let the BrowsingContext do this when it changes
2986 // the current window global, but that happens before this and we have a lot
2987 // of tests that depend on the specific ordering of messages.
2988 if (browsingContext->IsTopContent() &&
2989 !(aFlags & nsIWebProgressListener::LOCATION_CHANGE_SAME_DOCUMENT)) {
2990 browsingContext->UpdateSecurityState();
2992 return IPC_OK();
2995 mozilla::ipc::IPCResult BrowserParent::RecvOnStatusChange(
2996 const nsString& aMessage) {
2997 // We only collect status change notifications for the toplevel
2998 // BrowserParent.
2999 // FIXME: In the future, consider merging in status change information from
3000 // oop subframes.
3001 if (!GetBrowsingContext()->IsTopContent() ||
3002 !GetBrowsingContext()->GetWebProgress()) {
3003 return IPC_OK();
3006 GetBrowsingContext()->GetWebProgress()->OnStatusChange(nullptr, nullptr,
3007 NS_OK, aMessage.get());
3009 return IPC_OK();
3012 mozilla::ipc::IPCResult BrowserParent::RecvNavigationFinished() {
3013 nsCOMPtr<nsIBrowser> browser =
3014 mFrameElement ? mFrameElement->AsBrowser() : nullptr;
3016 if (browser) {
3017 browser->SetIsNavigating(false);
3020 return IPC_OK();
3023 mozilla::ipc::IPCResult BrowserParent::RecvNotifyContentBlockingEvent(
3024 const uint32_t& aEvent, const RequestData& aRequestData,
3025 const bool aBlocked, const nsACString& aTrackingOrigin,
3026 nsTArray<nsCString>&& aTrackingFullHashes,
3027 const Maybe<
3028 mozilla::ContentBlockingNotifier::StorageAccessPermissionGrantedReason>&
3029 aReason) {
3030 RefPtr<BrowsingContext> bc = GetBrowsingContext();
3032 if (!bc || bc->IsDiscarded()) {
3033 return IPC_OK();
3036 // Get the top-level browsing context.
3037 bc = bc->Top();
3038 RefPtr<dom::WindowGlobalParent> wgp =
3039 bc->Canonical()->GetCurrentWindowGlobal();
3041 // The WindowGlobalParent would be null while running the test
3042 // browser_339445.js. This is unexpected and we will address this in a
3043 // following bug. For now, we first workaround this issue.
3044 if (!wgp) {
3045 return IPC_OK();
3048 nsCOMPtr<nsIRequest> request = MakeAndAddRef<RemoteWebProgressRequest>(
3049 aRequestData.requestURI(), aRequestData.originalRequestURI(),
3050 aRequestData.matchedList());
3052 wgp->NotifyContentBlockingEvent(aEvent, request, aBlocked, aTrackingOrigin,
3053 aTrackingFullHashes, aReason);
3055 return IPC_OK();
3058 already_AddRefed<nsIBrowser> BrowserParent::GetBrowser() {
3059 nsCOMPtr<nsIBrowser> browser;
3060 RefPtr<Element> currentElement = mFrameElement;
3062 // In Responsive Design Mode, mFrameElement will be the <iframe mozbrowser>,
3063 // but we want the <xul:browser> that it is embedded in.
3064 while (currentElement) {
3065 browser = currentElement->AsBrowser();
3066 if (browser) {
3067 break;
3070 BrowsingContext* browsingContext =
3071 currentElement->OwnerDoc()->GetBrowsingContext();
3072 currentElement =
3073 browsingContext ? browsingContext->GetEmbedderElement() : nullptr;
3076 return browser.forget();
3079 already_AddRefed<CanonicalBrowsingContext>
3080 BrowserParent::BrowsingContextForWebProgress(
3081 const WebProgressData& aWebProgressData) {
3082 // Look up the BrowsingContext which this notification was fired for.
3083 if (aWebProgressData.browsingContext().IsNullOrDiscarded()) {
3084 NS_WARNING("WebProgress Ignored: BrowsingContext is null or discarded");
3085 return nullptr;
3087 RefPtr<CanonicalBrowsingContext> browsingContext =
3088 aWebProgressData.browsingContext().get_canonical();
3090 // Double-check that we actually manage this BrowsingContext, and are not
3091 // receiving a malformed or out-of-date request. browsingContext should either
3092 // be the toplevel one managed by this BrowserParent, or embedded within a
3093 // WindowGlobalParent managed by this BrowserParent.
3094 if (browsingContext != mBrowsingContext) {
3095 WindowGlobalParent* embedder = browsingContext->GetParentWindowContext();
3096 if (!embedder || embedder->GetBrowserParent() != this) {
3097 NS_WARNING("WebProgress Ignored: wrong embedder process");
3098 return nullptr;
3102 // The current process for this BrowsingContext may have changed since the
3103 // notification was fired. Don't fire events for it anymore, as ownership of
3104 // the BrowsingContext has been moved elsewhere.
3105 if (RefPtr<WindowGlobalParent> current =
3106 browsingContext->GetCurrentWindowGlobal();
3107 current && current->GetBrowserParent() != this) {
3108 NS_WARNING("WebProgress Ignored: no longer current window global");
3109 return nullptr;
3112 if (RefPtr<BrowsingContextWebProgress> progress =
3113 browsingContext->GetWebProgress()) {
3114 progress->SetLoadType(aWebProgressData.loadType());
3117 return browsingContext.forget();
3120 mozilla::ipc::IPCResult BrowserParent::RecvIntrinsicSizeOrRatioChanged(
3121 const Maybe<IntrinsicSize>& aIntrinsicSize,
3122 const Maybe<AspectRatio>& aIntrinsicRatio) {
3123 BrowserBridgeParent* bridge = GetBrowserBridgeParent();
3124 if (!bridge || !bridge->CanSend()) {
3125 return IPC_OK();
3128 Unused << bridge->SendIntrinsicSizeOrRatioChanged(aIntrinsicSize,
3129 aIntrinsicRatio);
3131 return IPC_OK();
3134 mozilla::ipc::IPCResult BrowserParent::RecvImageLoadComplete(
3135 const nsresult& aResult) {
3136 BrowserBridgeParent* bridge = GetBrowserBridgeParent();
3137 if (!bridge || !bridge->CanSend()) {
3138 return IPC_OK();
3141 Unused << bridge->SendImageLoadComplete(aResult);
3143 return IPC_OK();
3146 bool BrowserParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent) {
3147 nsCOMPtr<nsIWidget> textInputHandlingWidget = GetTextInputHandlingWidget();
3148 if (!textInputHandlingWidget) {
3149 return true;
3151 if (!mContentCache.HandleQueryContentEvent(aEvent, textInputHandlingWidget) ||
3152 NS_WARN_IF(aEvent.Failed())) {
3153 return true;
3155 switch (aEvent.mMessage) {
3156 case eQueryTextRect:
3157 case eQueryCaretRect:
3158 case eQueryEditorRect: {
3159 nsCOMPtr<nsIWidget> browserWidget = GetWidget();
3160 if (browserWidget != textInputHandlingWidget) {
3161 aEvent.mReply->mRect += nsLayoutUtils::WidgetToWidgetOffset(
3162 browserWidget, textInputHandlingWidget);
3164 aEvent.mReply->mRect = TransformChildToParent(aEvent.mReply->mRect);
3165 break;
3167 default:
3168 break;
3170 return true;
3173 bool BrowserParent::SendCompositionEvent(WidgetCompositionEvent& aEvent,
3174 uint32_t aCompositionId) {
3175 if (mIsDestroyed) {
3176 return false;
3179 // When the composition is handled in a remote process, we need to handle
3180 // commit/cancel result for composition with the composition ID to avoid
3181 // to abort newer composition. Therefore, we need to let the remote process
3182 // know the composition ID.
3183 MOZ_ASSERT(aCompositionId != 0);
3184 aEvent.mCompositionId = aCompositionId;
3186 if (!mContentCache.OnCompositionEvent(aEvent)) {
3187 return true;
3190 bool ret = Manager()->IsInputPriorityEventEnabled()
3191 ? PBrowserParent::SendCompositionEvent(aEvent)
3192 : PBrowserParent::SendNormalPriorityCompositionEvent(aEvent);
3193 if (NS_WARN_IF(!ret)) {
3194 return false;
3196 MOZ_ASSERT(aEvent.HasBeenPostedToRemoteProcess());
3197 return true;
3200 bool BrowserParent::SendSelectionEvent(WidgetSelectionEvent& aEvent) {
3201 if (mIsDestroyed) {
3202 return false;
3204 nsCOMPtr<nsIWidget> widget = GetWidget();
3205 if (!widget) {
3206 return true;
3208 mContentCache.OnSelectionEvent(aEvent);
3209 bool ret = Manager()->IsInputPriorityEventEnabled()
3210 ? PBrowserParent::SendSelectionEvent(aEvent)
3211 : PBrowserParent::SendNormalPrioritySelectionEvent(aEvent);
3212 if (NS_WARN_IF(!ret)) {
3213 return false;
3215 MOZ_ASSERT(aEvent.HasBeenPostedToRemoteProcess());
3216 aEvent.mSucceeded = true;
3217 return true;
3220 bool BrowserParent::SendInsertText(const nsString& aStringToInsert) {
3221 if (mIsDestroyed) {
3222 return false;
3224 return Manager()->IsInputPriorityEventEnabled()
3225 ? PBrowserParent::SendInsertText(aStringToInsert)
3226 : PBrowserParent::SendNormalPriorityInsertText(aStringToInsert);
3229 bool BrowserParent::SendPasteTransferable(
3230 IPCTransferableData&& aTransferableData, const bool& aIsPrivateData,
3231 nsIPrincipal* aRequestingPrincipal,
3232 const nsContentPolicyType& aContentPolicyType) {
3233 return PBrowserParent::SendPasteTransferable(
3234 std::move(aTransferableData), aIsPrivateData, aRequestingPrincipal,
3235 aContentPolicyType);
3238 /* static */
3239 void BrowserParent::SetTopLevelWebFocus(BrowserParent* aBrowserParent) {
3240 BrowserParent* old = GetFocused();
3241 if (aBrowserParent && !aBrowserParent->GetBrowserBridgeParent()) {
3242 // top-level Web content
3243 sTopLevelWebFocus = aBrowserParent;
3244 BrowserParent* bp = UpdateFocus();
3245 if (old != bp) {
3246 LOGBROWSERFOCUS(
3247 ("SetTopLevelWebFocus updated focus; old: %p, new: %p", old, bp));
3248 IMEStateManager::OnFocusMovedBetweenBrowsers(old, bp);
3253 /* static */
3254 void BrowserParent::UnsetTopLevelWebFocus(BrowserParent* aBrowserParent) {
3255 BrowserParent* old = GetFocused();
3256 if (sTopLevelWebFocus == aBrowserParent) {
3257 // top-level Web content
3258 sTopLevelWebFocus = nullptr;
3259 sFocus = nullptr;
3260 if (old) {
3261 LOGBROWSERFOCUS(
3262 ("UnsetTopLevelWebFocus moved focus to chrome; old: %p", old));
3263 IMEStateManager::OnFocusMovedBetweenBrowsers(old, nullptr);
3268 /* static */
3269 void BrowserParent::UpdateFocusFromBrowsingContext() {
3270 BrowserParent* old = GetFocused();
3271 BrowserParent* bp = UpdateFocus();
3272 if (old != bp) {
3273 LOGBROWSERFOCUS(
3274 ("UpdateFocusFromBrowsingContext updated focus; old: %p, new: %p", old,
3275 bp));
3276 IMEStateManager::OnFocusMovedBetweenBrowsers(old, bp);
3280 /* static */
3281 BrowserParent* BrowserParent::UpdateFocus() {
3282 if (!sTopLevelWebFocus) {
3283 sFocus = nullptr;
3284 return nullptr;
3286 nsFocusManager* fm = nsFocusManager::GetFocusManager();
3287 if (fm) {
3288 BrowsingContext* bc = fm->GetFocusedBrowsingContextInChrome();
3289 if (bc) {
3290 BrowsingContext* top = bc->Top();
3291 MOZ_ASSERT(top, "Should always have a top BrowsingContext.");
3292 CanonicalBrowsingContext* canonicalTop = top->Canonical();
3293 MOZ_ASSERT(canonicalTop,
3294 "Casting to canonical should always be possible in the parent "
3295 "process (top case).");
3296 WindowGlobalParent* globalTop = canonicalTop->GetCurrentWindowGlobal();
3297 if (globalTop) {
3298 RefPtr<BrowserParent> globalTopParent = globalTop->GetBrowserParent();
3299 if (sTopLevelWebFocus == globalTopParent) {
3300 CanonicalBrowsingContext* canonical = bc->Canonical();
3301 MOZ_ASSERT(
3302 canonical,
3303 "Casting to canonical should always be possible in the parent "
3304 "process.");
3305 WindowGlobalParent* global = canonical->GetCurrentWindowGlobal();
3306 if (global) {
3307 RefPtr<BrowserParent> parent = global->GetBrowserParent();
3308 sFocus = parent;
3309 return sFocus;
3311 LOGBROWSERFOCUS(
3312 ("Focused BrowsingContext did not have WindowGlobalParent."));
3314 } else {
3315 LOGBROWSERFOCUS(
3316 ("Top-level BrowsingContext did not have WindowGlobalParent."));
3320 sFocus = sTopLevelWebFocus;
3321 return sFocus;
3324 /* static */
3325 void BrowserParent::UnsetTopLevelWebFocusAll() {
3326 if (sTopLevelWebFocus) {
3327 UnsetTopLevelWebFocus(sTopLevelWebFocus);
3331 /* static */
3332 void BrowserParent::UnsetLastMouseRemoteTarget(BrowserParent* aBrowserParent) {
3333 if (sLastMouseRemoteTarget == aBrowserParent) {
3334 sLastMouseRemoteTarget = nullptr;
3338 mozilla::ipc::IPCResult BrowserParent::RecvRequestIMEToCommitComposition(
3339 const bool& aCancel, const uint32_t& aCompositionId, bool* aIsCommitted,
3340 nsString* aCommittedString) {
3341 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
3342 if (!widget) {
3343 *aIsCommitted = false;
3344 return IPC_OK();
3347 *aIsCommitted = mContentCache.RequestIMEToCommitComposition(
3348 widget, aCancel, aCompositionId, *aCommittedString);
3349 return IPC_OK();
3352 mozilla::ipc::IPCResult BrowserParent::RecvGetInputContext(
3353 widget::IMEState* aState) {
3354 nsCOMPtr<nsIWidget> widget = GetWidget();
3355 if (!widget) {
3356 *aState = widget::IMEState(IMEEnabled::Disabled,
3357 IMEState::OPEN_STATE_NOT_SUPPORTED);
3358 return IPC_OK();
3361 *aState = widget->GetInputContext().mIMEState;
3362 return IPC_OK();
3365 mozilla::ipc::IPCResult BrowserParent::RecvSetInputContext(
3366 const InputContext& aContext, const InputContextAction& aAction) {
3367 IMEStateManager::SetInputContextForChildProcess(this, aContext, aAction);
3368 return IPC_OK();
3371 bool BrowserParent::ReceiveMessage(const nsString& aMessage, bool aSync,
3372 StructuredCloneData* aData,
3373 nsTArray<StructuredCloneData>* aRetVal) {
3374 // If we're for an oop iframe, don't deliver messages to the wrong place.
3375 if (mBrowserBridgeParent) {
3376 return true;
3379 RefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
3380 if (frameLoader && frameLoader->GetFrameMessageManager()) {
3381 RefPtr<nsFrameMessageManager> manager =
3382 frameLoader->GetFrameMessageManager();
3384 manager->ReceiveMessage(mFrameElement, frameLoader, aMessage, aSync, aData,
3385 aRetVal, IgnoreErrors());
3387 return true;
3390 // nsIAuthPromptProvider
3392 // This method is largely copied from nsDocShell::GetAuthPrompt
3393 NS_IMETHODIMP
3394 BrowserParent::GetAuthPrompt(uint32_t aPromptReason, const nsIID& iid,
3395 void** aResult) {
3396 // we're either allowing auth, or it's a proxy request
3397 nsresult rv;
3398 nsCOMPtr<nsIPromptFactory> wwatch =
3399 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
3400 NS_ENSURE_SUCCESS(rv, rv);
3402 nsCOMPtr<nsPIDOMWindowOuter> window;
3403 RefPtr<Element> frame = mFrameElement;
3404 if (frame) window = frame->OwnerDoc()->GetWindow();
3406 // Get an auth prompter for our window so that the parenting
3407 // of the dialogs works as it should when using tabs.
3408 nsCOMPtr<nsISupports> prompt;
3409 rv = wwatch->GetPrompt(window, iid, getter_AddRefs(prompt));
3410 NS_ENSURE_SUCCESS(rv, rv);
3412 nsCOMPtr<nsILoginManagerAuthPrompter> prompter = do_QueryInterface(prompt);
3413 if (prompter) {
3414 prompter->SetBrowser(mFrameElement);
3417 *aResult = prompt.forget().take();
3418 return NS_OK;
3421 already_AddRefed<PColorPickerParent> BrowserParent::AllocPColorPickerParent(
3422 const nsString& aTitle, const nsString& aInitialColor,
3423 const nsTArray<nsString>& aDefaultColors) {
3424 return MakeAndAddRef<ColorPickerParent>(aTitle, aInitialColor,
3425 aDefaultColors);
3428 already_AddRefed<nsFrameLoader> BrowserParent::GetFrameLoader(
3429 bool aUseCachedFrameLoaderAfterDestroy) const {
3430 if (mIsDestroyed && !aUseCachedFrameLoaderAfterDestroy) {
3431 return nullptr;
3434 if (mFrameLoader) {
3435 RefPtr<nsFrameLoader> fl = mFrameLoader;
3436 return fl.forget();
3438 RefPtr<Element> frameElement(mFrameElement);
3439 RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(frameElement);
3440 return frameLoaderOwner ? frameLoaderOwner->GetFrameLoader() : nullptr;
3443 void BrowserParent::TryCacheDPIAndScale() {
3444 if (mDPI > 0) {
3445 return;
3448 const auto oldDefaultScale = mDefaultScale;
3449 nsCOMPtr<nsIWidget> widget = GetWidget();
3450 mDPI = widget ? widget->GetDPI() : nsIWidget::GetFallbackDPI();
3451 mRounding = widget ? widget->RoundsWidgetCoordinatesTo() : 1;
3452 mDefaultScale =
3453 widget ? widget->GetDefaultScale() : nsIWidget::GetFallbackDefaultScale();
3455 if (mDefaultScale != oldDefaultScale) {
3456 // The change of the default scale factor will affect the child dimensions
3457 // so we need to invalidate it.
3458 mUpdatedDimensions = false;
3462 void BrowserParent::ApzAwareEventRoutingToChild(
3463 ScrollableLayerGuid* aOutTargetGuid, uint64_t* aOutInputBlockId,
3464 nsEventStatus* aOutApzResponse) {
3465 // Let the widget know that the event will be sent to the child process,
3466 // which will (hopefully) send a confirmation notice back to APZ.
3467 // Do this even if APZ is off since we need it for swipe gesture support on
3468 // OS X without APZ.
3469 InputAPZContext::SetRoutedToChildProcess();
3471 if (AsyncPanZoomEnabled()) {
3472 if (aOutTargetGuid) {
3473 *aOutTargetGuid = InputAPZContext::GetTargetLayerGuid();
3475 // There may be cases where the APZ hit-testing code came to a different
3476 // conclusion than the main-thread hit-testing code as to where the event
3477 // is destined. In such cases the layersId of the APZ result may not match
3478 // the layersId of this RemoteLayerTreeOwner. In such cases the
3479 // main-thread hit- testing code "wins" so we need to update the guid to
3480 // reflect this.
3481 if (mRemoteLayerTreeOwner.IsInitialized()) {
3482 if (aOutTargetGuid->mLayersId != mRemoteLayerTreeOwner.GetLayersId()) {
3483 *aOutTargetGuid =
3484 ScrollableLayerGuid(mRemoteLayerTreeOwner.GetLayersId(), 0,
3485 ScrollableLayerGuid::NULL_SCROLL_ID);
3489 if (aOutInputBlockId) {
3490 *aOutInputBlockId = InputAPZContext::GetInputBlockId();
3492 if (aOutApzResponse) {
3493 *aOutApzResponse = InputAPZContext::GetApzResponse();
3495 // We can get here without there being an InputAPZContext on the stack
3496 // if a non-native event synthesization function (such as
3497 // nsIDOMWindowUtils.sendTouchEvent()) was used in the parent process to
3498 // synthesize an event that's targeting a content process. Such events do
3499 // not go through APZ. Without an InputAPZContext on the stack we pick up
3500 // the default value "eSentinel" which cannot be sent over IPC, so replace
3501 // it with "eIgnore" instead, which what APZ uses when it ignores an
3502 // event. If a caller needs the ability to synthesize a event with a
3503 // different APZ response, a native event synthesization function (such as
3504 // sendNativeTouchPoint()) can be used.
3505 if (*aOutApzResponse == nsEventStatus_eSentinel) {
3506 *aOutApzResponse = nsEventStatus_eIgnore;
3509 } else {
3510 if (aOutInputBlockId) {
3511 *aOutInputBlockId = 0;
3513 if (aOutApzResponse) {
3514 *aOutApzResponse = nsEventStatus_eIgnore;
3519 mozilla::ipc::IPCResult BrowserParent::RecvRespondStartSwipeEvent(
3520 const uint64_t& aInputBlockId, const bool& aStartSwipe) {
3521 if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
3522 widget->ReportSwipeStarted(aInputBlockId, aStartSwipe);
3524 return IPC_OK();
3527 bool BrowserParent::GetDocShellIsActive() {
3528 return mBrowsingContext && mBrowsingContext->IsActive();
3531 bool BrowserParent::GetHasPresented() { return mHasPresented; }
3533 bool BrowserParent::GetHasLayers() { return mHasLayers; }
3535 bool BrowserParent::GetRenderLayers() { return mRenderLayers; }
3537 void BrowserParent::SetRenderLayers(bool aEnabled) {
3538 if (aEnabled == mRenderLayers) {
3539 if (aEnabled && mHasLayers && mIsPreservingLayers) {
3540 // RenderLayers might be called when we've been preserving layers,
3541 // and already had layers uploaded. In that case, the MozLayerTreeReady
3542 // event will not naturally arrive, which can confuse the front-end
3543 // layer. So we fire the event here.
3544 RefPtr<BrowserParent> self = this;
3545 LayersObserverEpoch epoch = mLayerTreeEpoch;
3546 NS_DispatchToMainThread(NS_NewRunnableFunction(
3547 "dom::BrowserParent::RenderLayers", [self, epoch]() {
3548 MOZ_ASSERT(NS_IsMainThread());
3549 self->LayerTreeUpdate(epoch, true);
3550 }));
3553 return;
3556 // Preserve layers means that attempts to stop rendering layers
3557 // will be ignored.
3558 if (!aEnabled && mIsPreservingLayers) {
3559 return;
3562 mRenderLayers = aEnabled;
3564 SetRenderLayersInternal(aEnabled);
3567 void BrowserParent::SetRenderLayersInternal(bool aEnabled) {
3568 // Increment the epoch so that layer tree updates from previous
3569 // RenderLayers requests are ignored.
3570 mLayerTreeEpoch = mLayerTreeEpoch.Next();
3572 Unused << SendRenderLayers(aEnabled, mLayerTreeEpoch);
3574 // Ask the child to repaint/unload layers using the PHangMonitor
3575 // channel/thread (which may be less congested).
3576 if (aEnabled) {
3577 Manager()->PaintTabWhileInterruptingJS(this, mLayerTreeEpoch);
3578 } else {
3579 Manager()->UnloadLayersWhileInterruptingJS(this, mLayerTreeEpoch);
3583 bool BrowserParent::GetPriorityHint() { return mPriorityHint; }
3585 void BrowserParent::SetPriorityHint(bool aPriorityHint) {
3586 mPriorityHint = aPriorityHint;
3587 RecomputeProcessPriority();
3590 void BrowserParent::RecomputeProcessPriority() {
3591 auto* bc = GetBrowsingContext();
3592 ProcessPriorityManager::BrowserPriorityChanged(
3593 bc, bc->IsActive() || mPriorityHint);
3596 void BrowserParent::PreserveLayers(bool aPreserveLayers) {
3597 if (mIsPreservingLayers == aPreserveLayers) {
3598 return;
3600 mIsPreservingLayers = aPreserveLayers;
3601 Unused << SendPreserveLayers(aPreserveLayers);
3604 void BrowserParent::NotifyResolutionChanged() {
3605 if (mIsDestroyed) {
3606 return;
3608 // TryCacheDPIAndScale()'s cache is keyed off of
3609 // mDPI being greater than 0, so this invalidates it.
3610 mDPI = -1;
3611 TryCacheDPIAndScale();
3612 // If mDPI was set to -1 to invalidate it and then TryCacheDPIAndScale
3613 // fails to cache the values, then mDefaultScale.scale might be invalid.
3614 // We don't want to send that value to content. Just send -1 for it too in
3615 // that case.
3616 Unused << SendUIResolutionChanged(mDPI, mRounding,
3617 mDPI < 0 ? -1.0 : mDefaultScale.scale);
3620 bool BrowserParent::CanCancelContentJS(
3621 nsIRemoteTab::NavigationType aNavigationType, int32_t aNavigationIndex,
3622 nsIURI* aNavigationURI) const {
3623 // Pre-checking if we can cancel content js in the parent is only
3624 // supported when session history in the parent is enabled.
3625 if (!mozilla::SessionHistoryInParent()) {
3626 // If session history in the parent isn't enabled, this check will
3627 // be fully done in BrowserChild::CanCancelContentJS
3628 return true;
3631 nsCOMPtr<nsISHistory> history = mBrowsingContext->GetSessionHistory();
3633 if (!history) {
3634 // If there is no history we can't possibly know if it's ok to
3635 // cancel content js.
3636 return false;
3639 int32_t current;
3640 NS_ENSURE_SUCCESS(history->GetIndex(&current), false);
3642 if (current == -1) {
3643 // This tab has no history! Just return.
3644 return false;
3647 nsCOMPtr<nsISHEntry> entry;
3648 NS_ENSURE_SUCCESS(history->GetEntryAtIndex(current, getter_AddRefs(entry)),
3649 false);
3651 nsCOMPtr<nsIURI> currentURI = entry->GetURI();
3652 if (!currentURI->SchemeIs("http") && !currentURI->SchemeIs("https") &&
3653 !currentURI->SchemeIs("file")) {
3654 // Only cancel content JS for http(s) and file URIs. Other URIs are probably
3655 // internal and we should just let them run to completion.
3656 return false;
3659 if (aNavigationType == nsIRemoteTab::NAVIGATE_BACK) {
3660 aNavigationIndex = current - 1;
3661 } else if (aNavigationType == nsIRemoteTab::NAVIGATE_FORWARD) {
3662 aNavigationIndex = current + 1;
3663 } else if (aNavigationType == nsIRemoteTab::NAVIGATE_URL) {
3664 if (!aNavigationURI) {
3665 return false;
3668 if (aNavigationURI->SchemeIs("javascript")) {
3669 // "javascript:" URIs don't (necessarily) trigger navigation to a
3670 // different page, so don't allow the current page's JS to terminate.
3671 return false;
3674 // If navigating directly to a URL (e.g. via hitting Enter in the location
3675 // bar), then we can cancel anytime the next URL is different from the
3676 // current, *excluding* the ref ("#").
3677 bool equals;
3678 NS_ENSURE_SUCCESS(currentURI->EqualsExceptRef(aNavigationURI, &equals),
3679 false);
3680 return !equals;
3682 // Note: aNavigationType may also be NAVIGATE_INDEX, in which case we don't
3683 // need to do anything special.
3685 int32_t delta = aNavigationIndex > current ? 1 : -1;
3686 for (int32_t i = current + delta; i != aNavigationIndex + delta; i += delta) {
3687 nsCOMPtr<nsISHEntry> nextEntry;
3688 // If `i` happens to be negative, this call will fail (which is what we
3689 // would want to happen).
3690 NS_ENSURE_SUCCESS(history->GetEntryAtIndex(i, getter_AddRefs(nextEntry)),
3691 false);
3693 nsCOMPtr<nsISHEntry> laterEntry = delta == 1 ? nextEntry : entry;
3694 nsCOMPtr<nsIURI> thisURI = entry->GetURI();
3695 nsCOMPtr<nsIURI> nextURI = nextEntry->GetURI();
3697 // If we changed origin and the load wasn't in a subframe, we know it was
3698 // a full document load, so we can cancel the content JS safely.
3699 if (!laterEntry->GetIsSubFrame()) {
3700 nsAutoCString thisHost;
3701 NS_ENSURE_SUCCESS(thisURI->GetPrePath(thisHost), false);
3703 nsAutoCString nextHost;
3704 NS_ENSURE_SUCCESS(nextURI->GetPrePath(nextHost), false);
3706 if (!thisHost.Equals(nextHost)) {
3707 return true;
3711 entry = nextEntry;
3714 return false;
3717 void BrowserParent::SuppressDisplayport(bool aEnabled) {
3718 if (IsDestroyed()) {
3719 return;
3722 #ifdef DEBUG
3723 if (aEnabled) {
3724 mActiveSupressDisplayportCount++;
3725 } else {
3726 mActiveSupressDisplayportCount--;
3728 MOZ_ASSERT(mActiveSupressDisplayportCount >= 0);
3729 #endif
3731 Unused << SendSuppressDisplayport(aEnabled);
3734 void BrowserParent::NavigateByKey(bool aForward, bool aForDocumentNavigation) {
3735 Unused << SendNavigateByKey(aForward, aForDocumentNavigation);
3738 void BrowserParent::LayerTreeUpdate(const LayersObserverEpoch& aEpoch,
3739 bool aActive) {
3740 // Ignore updates if we're an out-of-process iframe. For oop iframes, our
3741 // |mFrameElement| is that of the top-level document, and so AsyncTabSwitcher
3742 // will treat MozLayerTreeReady / MozLayerTreeCleared events as if they came
3743 // from the top-level tab, which is wrong.
3745 // XXX: Should we still be updating |mHasLayers|?
3746 if (GetBrowserBridgeParent()) {
3747 return;
3750 // Ignore updates from old epochs. They might tell us that layers are
3751 // available when we've already sent a message to clear them. We can't trust
3752 // the update in that case since layers could disappear anytime after that.
3753 if (aEpoch != mLayerTreeEpoch || mIsDestroyed) {
3754 return;
3757 RefPtr<Element> frameElement = mFrameElement;
3758 if (!frameElement) {
3759 NS_WARNING("Could not locate target for layer tree message.");
3760 return;
3763 mHasLayers = aActive;
3765 RefPtr<Event> event = NS_NewDOMEvent(frameElement, nullptr, nullptr);
3766 if (aActive) {
3767 mHasPresented = true;
3768 event->InitEvent(u"MozLayerTreeReady"_ns, true, false);
3769 } else {
3770 event->InitEvent(u"MozLayerTreeCleared"_ns, true, false);
3772 event->SetTrusted(true);
3773 event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
3774 frameElement->DispatchEvent(*event);
3777 mozilla::ipc::IPCResult BrowserParent::RecvPaintWhileInterruptingJSNoOp(
3778 const LayersObserverEpoch& aEpoch) {
3779 // We sent a PaintWhileInterruptingJS message when layers were already
3780 // visible. In this case, we should act as if an update occurred even though
3781 // we already have the layers.
3782 LayerTreeUpdate(aEpoch, true);
3783 return IPC_OK();
3786 mozilla::ipc::IPCResult BrowserParent::RecvRemoteIsReadyToHandleInputEvents() {
3787 // When enabling input event prioritization, input events may preempt other
3788 // normal priority IPC messages. To prevent the input events preempt
3789 // PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to
3790 // notify the parent that BrowserChild is created and ready to handle input
3791 // events.
3792 SetReadyToHandleInputEvents();
3793 return IPC_OK();
3796 PPaymentRequestParent* BrowserParent::AllocPPaymentRequestParent() {
3797 RefPtr<PaymentRequestParent> actor = new PaymentRequestParent();
3798 return actor.forget().take();
3801 bool BrowserParent::DeallocPPaymentRequestParent(
3802 PPaymentRequestParent* aActor) {
3803 RefPtr<PaymentRequestParent> actor =
3804 dont_AddRef(static_cast<PaymentRequestParent*>(aActor));
3805 return true;
3808 nsresult BrowserParent::HandleEvent(Event* aEvent) {
3809 if (mIsDestroyed) {
3810 return NS_OK;
3813 nsAutoString eventType;
3814 aEvent->GetType(eventType);
3815 if (eventType.EqualsLiteral("MozUpdateWindowPos") ||
3816 eventType.EqualsLiteral("fullscreenchange")) {
3817 // Events that signify the window moving are used to update the position
3818 // and notify the BrowserChild.
3819 return UpdatePosition();
3821 return NS_OK;
3824 mozilla::ipc::IPCResult BrowserParent::RecvInvokeDragSession(
3825 nsTArray<IPCTransferableData>&& aTransferables, const uint32_t& aAction,
3826 Maybe<BigBuffer>&& aVisualDnDData, const uint32_t& aStride,
3827 const gfx::SurfaceFormat& aFormat, const LayoutDeviceIntRect& aDragRect,
3828 nsIPrincipal* aPrincipal, nsIContentSecurityPolicy* aCsp,
3829 const CookieJarSettingsArgs& aCookieJarSettingsArgs,
3830 const MaybeDiscarded<WindowContext>& aSourceWindowContext,
3831 const MaybeDiscarded<WindowContext>& aSourceTopWindowContext) {
3832 PresShell* presShell = mFrameElement->OwnerDoc()->GetPresShell();
3833 if (!presShell) {
3834 Unused << Manager()->SendEndDragSession(
3835 true, true, LayoutDeviceIntPoint(), 0,
3836 nsIDragService::DRAGDROP_ACTION_NONE);
3837 // Continue sending input events with input priority when stopping the dnd
3838 // session.
3839 Manager()->SetInputPriorityEventEnabled(true);
3840 return IPC_OK();
3843 nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
3844 net::CookieJarSettings::Deserialize(aCookieJarSettingsArgs,
3845 getter_AddRefs(cookieJarSettings));
3847 RefPtr<RemoteDragStartData> dragStartData = new RemoteDragStartData(
3848 this, std::move(aTransferables), aDragRect, aPrincipal, aCsp,
3849 cookieJarSettings, aSourceWindowContext.GetMaybeDiscarded(),
3850 aSourceTopWindowContext.GetMaybeDiscarded());
3852 if (aVisualDnDData) {
3853 const auto checkedSize = CheckedInt<size_t>(aDragRect.height) * aStride;
3854 if (checkedSize.isValid() &&
3855 aVisualDnDData->Size() >= checkedSize.value()) {
3856 dragStartData->SetVisualization(gfx::CreateDataSourceSurfaceFromData(
3857 gfx::IntSize(aDragRect.width, aDragRect.height), aFormat,
3858 aVisualDnDData->Data(), aStride));
3862 nsCOMPtr<nsIDragService> dragService =
3863 do_GetService("@mozilla.org/widget/dragservice;1");
3864 if (dragService) {
3865 dragService->MaybeAddChildProcess(Manager());
3868 presShell->GetPresContext()
3869 ->EventStateManager()
3870 ->BeginTrackingRemoteDragGesture(mFrameElement, dragStartData);
3872 return IPC_OK();
3875 bool BrowserParent::AsyncPanZoomEnabled() const {
3876 nsCOMPtr<nsIWidget> widget = GetWidget();
3877 return widget && widget->AsyncPanZoomEnabled();
3880 void BrowserParent::StartPersistence(
3881 CanonicalBrowsingContext* aContext,
3882 nsIWebBrowserPersistDocumentReceiver* aRecv, ErrorResult& aRv) {
3883 auto* actor = new WebBrowserPersistDocumentParent();
3884 actor->SetOnReady(aRecv);
3885 bool ok = Manager()->SendPWebBrowserPersistDocumentConstructor(actor, this,
3886 aContext);
3887 if (!ok) {
3888 aRv.Throw(NS_ERROR_FAILURE);
3890 // (The actor will be destroyed on constructor failure.)
3893 mozilla::ipc::IPCResult BrowserParent::RecvLookUpDictionary(
3894 const nsString& aText, nsTArray<FontRange>&& aFontRangeArray,
3895 const bool& aIsVertical, const LayoutDeviceIntPoint& aPoint) {
3896 nsCOMPtr<nsIWidget> widget = GetWidget();
3897 if (!widget) {
3898 return IPC_OK();
3901 widget->LookUpDictionary(aText, aFontRangeArray, aIsVertical,
3902 TransformChildToParent(aPoint));
3903 return IPC_OK();
3906 mozilla::ipc::IPCResult BrowserParent::RecvShowCanvasPermissionPrompt(
3907 const nsCString& aOrigin, const bool& aHideDoorHanger) {
3908 nsCOMPtr<nsIBrowser> browser =
3909 mFrameElement ? mFrameElement->AsBrowser() : nullptr;
3910 if (!browser) {
3911 // If the tab is being closed, the browser may not be available.
3912 // In this case we can ignore the request.
3913 return IPC_OK();
3915 nsCOMPtr<nsIObserverService> os = services::GetObserverService();
3916 if (!os) {
3917 return IPC_FAIL_NO_REASON(this);
3919 nsresult rv = os->NotifyObservers(
3920 browser,
3921 aHideDoorHanger ? "canvas-permissions-prompt-hide-doorhanger"
3922 : "canvas-permissions-prompt",
3923 NS_ConvertUTF8toUTF16(aOrigin).get());
3924 if (NS_FAILED(rv)) {
3925 return IPC_FAIL_NO_REASON(this);
3927 return IPC_OK();
3930 mozilla::ipc::IPCResult BrowserParent::RecvVisitURI(
3931 nsIURI* aURI, nsIURI* aLastVisitedURI, const uint32_t& aFlags,
3932 const uint64_t& aBrowserId) {
3933 if (!aURI) {
3934 return IPC_FAIL_NO_REASON(this);
3936 RefPtr<nsIWidget> widget = GetWidget();
3937 if (NS_WARN_IF(!widget)) {
3938 return IPC_OK();
3940 nsCOMPtr<IHistory> history = components::History::Service();
3941 if (history) {
3942 Unused << history->VisitURI(widget, aURI, aLastVisitedURI, aFlags,
3943 aBrowserId);
3945 return IPC_OK();
3948 mozilla::ipc::IPCResult BrowserParent::RecvQueryVisitedState(
3949 nsTArray<RefPtr<nsIURI>>&& aURIs) {
3950 #ifdef MOZ_ANDROID_HISTORY
3951 nsCOMPtr<IHistory> history = components::History::Service();
3952 if (NS_WARN_IF(!history)) {
3953 return IPC_OK();
3955 RefPtr<nsIWidget> widget = GetWidget();
3956 if (NS_WARN_IF(!widget)) {
3957 return IPC_OK();
3960 // FIXME(emilio): Is this check really needed?
3961 for (nsIURI* uri : aURIs) {
3962 if (!uri) {
3963 return IPC_FAIL(this, "Received null URI");
3967 auto* gvHistory = static_cast<GeckoViewHistory*>(history.get());
3968 gvHistory->QueryVisitedState(widget, mManager, std::move(aURIs));
3969 return IPC_OK();
3970 #else
3971 return IPC_FAIL(this, "QueryVisitedState is Android-only");
3972 #endif
3975 void BrowserParent::LiveResizeStarted() { SuppressDisplayport(true); }
3977 void BrowserParent::LiveResizeStopped() { SuppressDisplayport(false); }
3979 void BrowserParent::SetBrowserBridgeParent(BrowserBridgeParent* aBrowser) {
3980 // We should either be clearing out our reference to a browser bridge, or not
3981 // have either a browser bridge, browser host, or owner content yet.
3982 MOZ_ASSERT(!aBrowser ||
3983 (!mBrowserBridgeParent && !mBrowserHost && !mFrameElement));
3984 mBrowserBridgeParent = aBrowser;
3987 void BrowserParent::SetBrowserHost(BrowserHost* aBrowser) {
3988 // We should either be clearing out our reference to a browser host, or not
3989 // have either a browser bridge, browser host, or owner content yet.
3990 MOZ_ASSERT(!aBrowser ||
3991 (!mBrowserBridgeParent && !mBrowserHost && !mFrameElement));
3992 mBrowserHost = aBrowser;
3995 mozilla::ipc::IPCResult BrowserParent::RecvSetSystemFont(
3996 const nsCString& aFontName) {
3997 nsCOMPtr<nsIWidget> widget = GetWidget();
3998 if (widget) {
3999 widget->SetSystemFont(aFontName);
4001 return IPC_OK();
4004 mozilla::ipc::IPCResult BrowserParent::RecvGetSystemFont(nsCString* aFontName) {
4005 nsCOMPtr<nsIWidget> widget = GetWidget();
4006 if (widget) {
4007 widget->GetSystemFont(*aFontName);
4009 return IPC_OK();
4012 mozilla::ipc::IPCResult BrowserParent::RecvMaybeFireEmbedderLoadEvents(
4013 EmbedderElementEventType aFireEventAtEmbeddingElement) {
4014 BrowserBridgeParent* bridge = GetBrowserBridgeParent();
4015 if (!bridge) {
4016 NS_WARNING("Received `load` event on unbridged BrowserParent!");
4017 return IPC_OK();
4020 Unused << bridge->SendMaybeFireEmbedderLoadEvents(
4021 aFireEventAtEmbeddingElement);
4022 return IPC_OK();
4025 mozilla::ipc::IPCResult BrowserParent::RecvScrollRectIntoView(
4026 const nsRect& aRect, const ScrollAxis& aVertical,
4027 const ScrollAxis& aHorizontal, const ScrollFlags& aScrollFlags,
4028 const int32_t& aAppUnitsPerDevPixel) {
4029 BrowserBridgeParent* bridge = GetBrowserBridgeParent();
4030 if (!bridge || !bridge->CanSend()) {
4031 return IPC_OK();
4034 Unused << bridge->SendScrollRectIntoView(aRect, aVertical, aHorizontal,
4035 aScrollFlags, aAppUnitsPerDevPixel);
4036 return IPC_OK();
4039 mozilla::ipc::IPCResult BrowserParent::RecvIsWindowSupportingProtectedMedia(
4040 const uint64_t& aOuterWindowID,
4041 IsWindowSupportingProtectedMediaResolver&& aResolve) {
4042 #ifdef XP_WIN
4043 bool isFxrWindow =
4044 FxRWindowManager::GetInstance()->IsFxRWindow(aOuterWindowID);
4045 aResolve(!isFxrWindow);
4046 #else
4047 # ifdef FUZZING_SNAPSHOT
4048 return IPC_FAIL(this, "Should only be called on Windows");
4049 # endif
4050 MOZ_CRASH("Should only be called on Windows");
4051 #endif
4053 return IPC_OK();
4056 mozilla::ipc::IPCResult BrowserParent::RecvIsWindowSupportingWebVR(
4057 const uint64_t& aOuterWindowID,
4058 IsWindowSupportingWebVRResolver&& aResolve) {
4059 #ifdef XP_WIN
4060 bool isFxrWindow =
4061 FxRWindowManager::GetInstance()->IsFxRWindow(aOuterWindowID);
4062 aResolve(!isFxrWindow);
4063 #else
4064 aResolve(true);
4065 #endif
4067 return IPC_OK();
4070 static BrowserParent* GetTopLevelBrowserParent(BrowserParent* aBrowserParent) {
4071 MOZ_ASSERT(aBrowserParent);
4072 BrowserParent* parent = aBrowserParent;
4073 while (BrowserBridgeParent* bridge = parent->GetBrowserBridgeParent()) {
4074 parent = bridge->Manager();
4076 return parent;
4079 mozilla::ipc::IPCResult BrowserParent::RecvRequestPointerLock(
4080 RequestPointerLockResolver&& aResolve) {
4081 nsCString error;
4082 if (sTopLevelWebFocus != GetTopLevelBrowserParent(this)) {
4083 error = "PointerLockDeniedNotFocused";
4084 } else if (!PointerLockManager::SetLockedRemoteTarget(this)) {
4085 error = "PointerLockDeniedInUse";
4086 } else {
4087 PointerEventHandler::ReleaseAllPointerCaptureRemoteTarget();
4089 aResolve(error);
4090 return IPC_OK();
4093 mozilla::ipc::IPCResult BrowserParent::RecvReleasePointerLock() {
4094 MOZ_ASSERT_IF(PointerLockManager::GetLockedRemoteTarget(),
4095 PointerLockManager::GetLockedRemoteTarget() == this);
4096 PointerLockManager::ReleaseLockedRemoteTarget(this);
4097 return IPC_OK();
4100 mozilla::ipc::IPCResult BrowserParent::RecvRequestPointerCapture(
4101 const uint32_t& aPointerId, RequestPointerCaptureResolver&& aResolve) {
4102 aResolve(
4103 PointerEventHandler::SetPointerCaptureRemoteTarget(aPointerId, this));
4104 return IPC_OK();
4107 mozilla::ipc::IPCResult BrowserParent::RecvReleasePointerCapture(
4108 const uint32_t& aPointerId) {
4109 PointerEventHandler::ReleasePointerCaptureRemoteTarget(aPointerId);
4110 return IPC_OK();
4113 mozilla::ipc::IPCResult BrowserParent::RecvShowDynamicToolbar() {
4114 #if defined(MOZ_WIDGET_ANDROID)
4115 nsCOMPtr<nsIWidget> widget = GetTopLevelWidget();
4116 if (!widget) {
4117 return IPC_OK();
4120 RefPtr<nsWindow> window = nsWindow::From(widget);
4121 if (!window) {
4122 return IPC_OK();
4125 window->ShowDynamicToolbar();
4126 #endif // defined(MOZ_WIDGET_ANDROID)
4127 return IPC_OK();
4130 } // namespace dom
4131 } // namespace mozilla