Bug 1861467 - [wpt-sync] Update web-platform-tests to eedf737ce39c512d0ca3471f988972e...
[gecko.git] / dom / ipc / BrowserParent.cpp
blobfdb56438da0a0c46a9e2af39f2586bc94e1fb010
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 mRect(0, 0, 0, 0),
288 mDimensions(0, 0),
289 mDPI(0),
290 mRounding(0),
291 mDefaultScale(0),
292 mUpdatedDimensions(false),
293 mSizeMode(nsSizeMode_Normal),
294 mCreatingWindow(false),
295 mVsyncParent(nullptr),
296 mMarkedDestroying(false),
297 mIsDestroyed(false),
298 mRemoteTargetSetsCursor(false),
299 mIsPreservingLayers(false),
300 mRenderLayers(true),
301 mPriorityHint(false),
302 mHasLayers(false),
303 mHasPresented(false),
304 mIsReadyToHandleInputEvents(false),
305 mIsMouseEnterIntoWidgetEventSuppressed(false),
306 mLockedNativePointer(false),
307 mShowingTooltip(false) {
308 MOZ_ASSERT(aManager);
310 RequestingAccessKeyEventData::OnBrowserParentCreated();
312 // When the input event queue is disabled, we don't need to handle the case
313 // that some input events are dispatched before PBrowserConstructor.
314 mIsReadyToHandleInputEvents = !ContentParent::IsInputEventQueueSupported();
316 // Make sure to compute our process priority if needed before the block of
317 // code below. This makes sure the block below prioritizes our process if
318 // needed.
319 if (aBrowsingContext->IsTop()) {
320 RecomputeProcessPriority();
323 // If we're in a BC tree that is active with respect to the priority manager,
324 // ensure that this new BrowserParent is marked as active. This ensures that
325 // the process will be prioritized in a cross-site iframe navigation in an
326 // active tab, and also that the process is correctly prioritized if we got
327 // created for a browsing context which was already active.
328 if (aBrowsingContext->Top()->IsPriorityActive()) {
329 ProcessPriorityManager::BrowserPriorityChanged(this, true);
333 BrowserParent::~BrowserParent() {
334 RequestingAccessKeyEventData::OnBrowserParentDestroyed();
337 /* static */
338 BrowserParent* BrowserParent::GetFocused() { return sFocus; }
340 /* static */
341 BrowserParent* BrowserParent::GetLastMouseRemoteTarget() {
342 return sLastMouseRemoteTarget;
345 /*static*/
346 BrowserParent* BrowserParent::GetFrom(nsFrameLoader* aFrameLoader) {
347 if (!aFrameLoader) {
348 return nullptr;
350 return aFrameLoader->GetBrowserParent();
353 /*static*/
354 BrowserParent* BrowserParent::GetFrom(PBrowserParent* aBrowserParent) {
355 return static_cast<BrowserParent*>(aBrowserParent);
358 /*static*/
359 BrowserParent* BrowserParent::GetFrom(nsIContent* aContent) {
360 RefPtr<nsFrameLoaderOwner> loaderOwner = do_QueryObject(aContent);
361 if (!loaderOwner) {
362 return nullptr;
364 RefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
365 return GetFrom(frameLoader);
368 /* static */
369 BrowserParent* BrowserParent::GetBrowserParentFromLayersId(
370 layers::LayersId aLayersId) {
371 if (!sLayerToBrowserParentTable) {
372 return nullptr;
374 return sLayerToBrowserParentTable->Get(uint64_t(aLayersId));
377 /*static*/
378 TabId BrowserParent::GetTabIdFrom(nsIDocShell* docShell) {
379 nsCOMPtr<nsIBrowserChild> browserChild(BrowserChild::GetFrom(docShell));
380 if (browserChild) {
381 return static_cast<BrowserChild*>(browserChild.get())->GetTabId();
383 return TabId(0);
386 void BrowserParent::AddBrowserParentToTable(layers::LayersId aLayersId,
387 BrowserParent* aBrowserParent) {
388 if (!sLayerToBrowserParentTable) {
389 sLayerToBrowserParentTable = new LayerToBrowserParentTable();
391 sLayerToBrowserParentTable->InsertOrUpdate(uint64_t(aLayersId),
392 aBrowserParent);
395 void BrowserParent::RemoveBrowserParentFromTable(layers::LayersId aLayersId) {
396 if (!sLayerToBrowserParentTable) {
397 return;
399 sLayerToBrowserParentTable->Remove(uint64_t(aLayersId));
400 if (sLayerToBrowserParentTable->Count() == 0) {
401 delete sLayerToBrowserParentTable;
402 sLayerToBrowserParentTable = nullptr;
406 already_AddRefed<nsILoadContext> BrowserParent::GetLoadContext() {
407 return do_AddRef(mBrowsingContext);
411 * Will return nullptr if there is no outer window available for the
412 * document hosting the owner element of this BrowserParent. Also will return
413 * nullptr if that outer window is in the process of closing.
415 already_AddRefed<nsPIDOMWindowOuter> BrowserParent::GetParentWindowOuter() {
416 nsCOMPtr<nsIContent> frame = GetOwnerElement();
417 if (!frame) {
418 return nullptr;
421 nsCOMPtr<nsPIDOMWindowOuter> parent = frame->OwnerDoc()->GetWindow();
422 if (!parent || parent->Closed()) {
423 return nullptr;
426 return parent.forget();
429 already_AddRefed<nsIWidget> BrowserParent::GetTopLevelWidget() {
430 if (RefPtr<Element> element = mFrameElement) {
431 if (PresShell* presShell = element->OwnerDoc()->GetPresShell()) {
432 return do_AddRef(presShell->GetViewManager()->GetRootWidget());
435 return nullptr;
438 already_AddRefed<nsIWidget> BrowserParent::GetTextInputHandlingWidget() const {
439 if (!mFrameElement) {
440 return nullptr;
442 PresShell* presShell = mFrameElement->OwnerDoc()->GetPresShell();
443 if (!presShell) {
444 return nullptr;
446 nsPresContext* presContext = presShell->GetPresContext();
447 if (!presContext) {
448 return nullptr;
450 nsCOMPtr<nsIWidget> widget = presContext->GetTextInputHandlingWidget();
451 return widget.forget();
454 already_AddRefed<nsIWidget> BrowserParent::GetWidget() const {
455 if (!mFrameElement) {
456 return nullptr;
458 nsCOMPtr<nsIWidget> widget = nsContentUtils::WidgetForContent(mFrameElement);
459 if (!widget) {
460 widget = nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc());
462 return widget.forget();
465 already_AddRefed<nsIWidget> BrowserParent::GetDocWidget() const {
466 if (!mFrameElement) {
467 return nullptr;
469 return do_AddRef(
470 nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc()));
473 nsIXULBrowserWindow* BrowserParent::GetXULBrowserWindow() {
474 if (!mFrameElement) {
475 return nullptr;
478 nsCOMPtr<nsIDocShell> docShell = mFrameElement->OwnerDoc()->GetDocShell();
479 if (!docShell) {
480 return nullptr;
483 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
484 docShell->GetTreeOwner(getter_AddRefs(treeOwner));
485 if (!treeOwner) {
486 return nullptr;
489 nsCOMPtr<nsIAppWindow> window = do_GetInterface(treeOwner);
490 if (!window) {
491 return nullptr;
494 nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow;
495 window->GetXULBrowserWindow(getter_AddRefs(xulBrowserWindow));
496 return xulBrowserWindow;
499 uint32_t BrowserParent::GetMaxTouchPoints(Element* aElement) {
500 if (!aElement) {
501 return 0;
504 if (StaticPrefs::dom_maxtouchpoints_testing_value() >= 0) {
505 return StaticPrefs::dom_maxtouchpoints_testing_value();
508 nsIWidget* widget = nsContentUtils::WidgetForDocument(aElement->OwnerDoc());
509 return widget ? widget->GetMaxTouchPoints() : 0;
512 a11y::DocAccessibleParent* BrowserParent::GetTopLevelDocAccessible() const {
513 #ifdef ACCESSIBILITY
514 // XXX Consider managing non top level PDocAccessibles with their parent
515 // document accessible.
516 const ManagedContainer<PDocAccessibleParent>& docs =
517 ManagedPDocAccessibleParent();
518 for (auto* key : docs) {
519 auto* doc = static_cast<a11y::DocAccessibleParent*>(key);
520 // We want the document for this BrowserParent even if it's for an
521 // embedded out-of-process iframe. Therefore, we use
522 // IsTopLevelInContentProcess. In contrast, using IsToplevel would only
523 // include documents that aren't embedded; e.g. tab documents.
524 if (doc->IsTopLevelInContentProcess() && !doc->IsShutdown()) {
525 return doc;
528 #endif
529 return nullptr;
532 LayersId BrowserParent::GetLayersId() const {
533 if (!mRemoteLayerTreeOwner.IsInitialized()) {
534 return LayersId{};
536 return mRemoteLayerTreeOwner.GetLayersId();
539 BrowserBridgeParent* BrowserParent::GetBrowserBridgeParent() const {
540 return mBrowserBridgeParent;
543 BrowserHost* BrowserParent::GetBrowserHost() const { return mBrowserHost; }
545 ParentShowInfo BrowserParent::GetShowInfo() {
546 TryCacheDPIAndScale();
547 if (mFrameElement) {
548 nsAutoString name;
549 mFrameElement->GetAttr(nsGkAtoms::name, name);
550 bool isTransparent =
551 nsContentUtils::IsChromeDoc(mFrameElement->OwnerDoc()) &&
552 mFrameElement->HasAttr(nsGkAtoms::transparent);
553 return ParentShowInfo(name, false, isTransparent, mDPI, mRounding,
554 mDefaultScale.scale);
557 return ParentShowInfo(u""_ns, false, false, mDPI, mRounding,
558 mDefaultScale.scale);
561 already_AddRefed<nsIPrincipal> BrowserParent::GetContentPrincipal() const {
562 nsCOMPtr<nsIBrowser> browser =
563 mFrameElement ? mFrameElement->AsBrowser() : nullptr;
564 NS_ENSURE_TRUE(browser, nullptr);
566 RefPtr<nsIPrincipal> principal;
568 nsresult rv;
569 rv = browser->GetContentPrincipal(getter_AddRefs(principal));
570 NS_ENSURE_SUCCESS(rv, nullptr);
572 return principal.forget();
575 void BrowserParent::SetOwnerElement(Element* aElement) {
576 // If we held previous content then unregister for its events.
577 RemoveWindowListeners();
579 // If we change top-level documents then we need to change our
580 // registration with them.
581 RefPtr<nsPIWindowRoot> curTopLevelWin, newTopLevelWin;
582 if (mFrameElement) {
583 curTopLevelWin = nsContentUtils::GetWindowRoot(mFrameElement->OwnerDoc());
585 if (aElement) {
586 newTopLevelWin = nsContentUtils::GetWindowRoot(aElement->OwnerDoc());
588 bool isSameTopLevelWin = curTopLevelWin == newTopLevelWin;
589 if (mBrowserHost && curTopLevelWin && !isSameTopLevelWin) {
590 curTopLevelWin->RemoveBrowser(mBrowserHost);
593 // Update to the new content, and register to listen for events from it.
594 mFrameElement = aElement;
596 if (mBrowserHost && newTopLevelWin && !isSameTopLevelWin) {
597 newTopLevelWin->AddBrowser(mBrowserHost);
600 #if defined(XP_WIN) && defined(ACCESSIBILITY)
601 if (!mIsDestroyed) {
602 uintptr_t newWindowHandle = 0;
603 if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
604 newWindowHandle =
605 reinterpret_cast<uintptr_t>(widget->GetNativeData(NS_NATIVE_WINDOW));
607 Unused << SendUpdateNativeWindowHandle(newWindowHandle);
608 a11y::DocAccessibleParent* doc = GetTopLevelDocAccessible();
609 if (doc) {
610 HWND hWnd = reinterpret_cast<HWND>(doc->GetEmulatedWindowHandle());
611 if (hWnd) {
612 HWND parentHwnd = reinterpret_cast<HWND>(newWindowHandle);
613 if (parentHwnd != ::GetParent(hWnd)) {
614 ::SetParent(hWnd, parentHwnd);
619 #endif
621 AddWindowListeners();
623 // The DPI depends on our frame element's widget, so invalidate now in case
624 // we've tried to cache it already.
625 mDPI = -1;
626 TryCacheDPIAndScale();
628 if (mRemoteLayerTreeOwner.IsInitialized()) {
629 mRemoteLayerTreeOwner.OwnerContentChanged();
632 // Set our BrowsingContext's embedder if we're not embedded within a
633 // BrowserBridgeParent.
634 if (!GetBrowserBridgeParent() && mBrowsingContext && mFrameElement) {
635 mBrowsingContext->SetEmbedderElement(mFrameElement);
638 UpdateVsyncParentVsyncDispatcher();
640 VisitChildren([aElement](BrowserBridgeParent* aBrowser) {
641 if (auto* browserParent = aBrowser->GetBrowserParent()) {
642 browserParent->SetOwnerElement(aElement);
647 void BrowserParent::CacheFrameLoader(nsFrameLoader* aFrameLoader) {
648 mFrameLoader = aFrameLoader;
651 void BrowserParent::AddWindowListeners() {
652 if (mFrameElement) {
653 if (nsCOMPtr<nsPIDOMWindowOuter> window =
654 mFrameElement->OwnerDoc()->GetWindow()) {
655 nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
656 if (eventTarget) {
657 eventTarget->AddEventListener(u"MozUpdateWindowPos"_ns, this, false,
658 false);
659 eventTarget->AddEventListener(u"fullscreenchange"_ns, this, false,
660 false);
666 void BrowserParent::RemoveWindowListeners() {
667 if (mFrameElement && mFrameElement->OwnerDoc()->GetWindow()) {
668 nsCOMPtr<nsPIDOMWindowOuter> window =
669 mFrameElement->OwnerDoc()->GetWindow();
670 nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
671 if (eventTarget) {
672 eventTarget->RemoveEventListener(u"MozUpdateWindowPos"_ns, this, false);
673 eventTarget->RemoveEventListener(u"fullscreenchange"_ns, this, false);
678 void BrowserParent::Deactivated() {
679 if (mShowingTooltip) {
680 // Reuse the normal tooltip hiding method.
681 mozilla::Unused << RecvHideTooltip();
683 UnlockNativePointer();
684 UnsetTopLevelWebFocus(this);
685 UnsetLastMouseRemoteTarget(this);
686 PointerLockManager::ReleaseLockedRemoteTarget(this);
687 PointerEventHandler::ReleasePointerCaptureRemoteTarget(this);
688 PresShell::ReleaseCapturingRemoteTarget(this);
689 ProcessPriorityManager::BrowserPriorityChanged(this, /* aPriority = */ false);
692 void BrowserParent::Destroy() {
693 // Aggressively release the window to avoid leaking the world in shutdown
694 // corner cases.
695 mBrowserDOMWindow = nullptr;
697 if (mIsDestroyed) {
698 return;
701 Deactivated();
703 RemoveWindowListeners();
705 #ifdef ACCESSIBILITY
706 if (a11y::DocAccessibleParent* tabDoc = GetTopLevelDocAccessible()) {
707 # if defined(ANDROID)
708 MonitorAutoLock mal(nsAccessibilityService::GetAndroidMonitor());
709 # endif
710 tabDoc->Destroy();
712 #endif
715 // The following sequence assumes that the keepalive state does not change
716 // between the calls, but our ThreadsafeHandle might be accessed from other
717 // threads in the meantime.
718 RecursiveMutexAutoLock lock(Manager()->ThreadsafeHandleMutex());
720 // If we are shutting down everything or we know to be the last
721 // BrowserParent, signal the impending shutdown early to the content process
722 // to avoid to run the SendDestroy before we know we are ExpectingShutdown.
723 Manager()->NotifyTabWillDestroy();
725 // If this fails, it's most likely due to a content-process crash, and
726 // auto-cleanup will kick in. Otherwise, the child side will destroy itself
727 // and send back __delete__().
728 (void)SendDestroy();
729 mIsDestroyed = true;
731 Manager()->NotifyTabDestroying();
734 // This `AddKeepAlive` will be cleared if `mMarkedDestroying` is set in
735 // `ActorDestroy`. Out of caution, we don't add the `KeepAlive` if our IPC
736 // actor has somehow already been destroyed, as that would mean `ActorDestroy`
737 // won't be called.
738 if (CanRecv()) {
739 mBrowsingContext->Group()->AddKeepAlive();
742 mMarkedDestroying = true;
745 mozilla::ipc::IPCResult BrowserParent::RecvDidUnsuppressPainting() {
746 if (!mFrameElement) {
747 return IPC_OK();
749 nsSubDocumentFrame* subdocFrame =
750 do_QueryFrame(mFrameElement->GetPrimaryFrame());
751 if (subdocFrame && subdocFrame->HasRetainedPaintData()) {
752 subdocFrame->ClearRetainedPaintData();
754 return IPC_OK();
757 mozilla::ipc::IPCResult BrowserParent::RecvEnsureLayersConnected(
758 CompositorOptions* aCompositorOptions) {
759 if (mRemoteLayerTreeOwner.IsInitialized()) {
760 mRemoteLayerTreeOwner.EnsureLayersConnected(aCompositorOptions);
762 return IPC_OK();
765 void BrowserParent::ActorDestroy(ActorDestroyReason why) {
766 Manager()->NotifyTabDestroyed(mTabId, mMarkedDestroying);
768 ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
769 if (cpm) {
770 cpm->UnregisterRemoteFrame(mTabId);
773 if (mRemoteLayerTreeOwner.IsInitialized()) {
774 auto layersId = mRemoteLayerTreeOwner.GetLayersId();
775 if (mFrameElement) {
776 nsSubDocumentFrame* f = do_QueryFrame(mFrameElement->GetPrimaryFrame());
777 if (f && f->HasRetainedPaintData() &&
778 f->GetRemotePaintData().mLayersId == layersId) {
779 f->ClearRetainedPaintData();
783 // It's important to unmap layers after the remote browser has been
784 // destroyed, otherwise it may still send messages to the compositor which
785 // will reject them, causing assertions.
786 RemoveBrowserParentFromTable(layersId);
787 mRemoteLayerTreeOwner.Destroy();
790 // Even though BrowserParent::Destroy calls this, we need to do it here too in
791 // case of a crash.
792 Deactivated();
794 if (why == AbnormalShutdown) {
795 // dom_reporting_header must also be enabled for the report to be sent.
796 if (StaticPrefs::dom_reporting_crash_enabled()) {
797 nsCOMPtr<nsIPrincipal> principal = GetContentPrincipal();
799 if (principal) {
800 nsAutoCString crash_reason;
801 CrashReporter::GetAnnotation(OtherPid(),
802 CrashReporter::Annotation::MozCrashReason,
803 crash_reason);
804 // FIXME(arenevier): Find a less fragile way to identify that a crash
805 // was caused by OOM
806 bool is_oom = false;
807 if (crash_reason == "OOM" || crash_reason == "OOM!" ||
808 StringBeginsWith(crash_reason, "[unhandlable oom]"_ns) ||
809 StringBeginsWith(crash_reason, "Unhandlable OOM"_ns)) {
810 is_oom = true;
813 CrashReport::Deliver(principal, is_oom);
818 // If we were shutting down normally, we held a reference to our
819 // BrowsingContextGroup in `BrowserParent::Destroy`. Clear that reference
820 // here.
821 if (mMarkedDestroying) {
822 mBrowsingContext->Group()->RemoveKeepAlive();
825 // Tell our embedder that the tab is now going away unless we're an
826 // out-of-process iframe.
827 RefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
828 if (frameLoader) {
829 ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr);
831 if (mBrowsingContext->IsTop()) {
832 // If this is a top-level BrowsingContext, tell the frameloader it's time
833 // to go away. Otherwise, this is a subframe crash, and we can keep the
834 // frameloader around.
835 frameLoader->DestroyComplete();
838 // If this was a crash, tell our nsFrameLoader to fire crash events.
839 if (why == AbnormalShutdown) {
840 frameLoader->MaybeNotifyCrashed(mBrowsingContext, Manager()->ChildID(),
841 GetIPCChannel());
842 } else if (why == ManagedEndpointDropped) {
843 // If we instead failed due to a constructor error, don't include process
844 // information, as the process did not crash.
845 frameLoader->MaybeNotifyCrashed(mBrowsingContext, ContentParentId{},
846 nullptr);
850 mFrameLoader = nullptr;
852 // If we were destroyed due to our ManagedEndpoints being dropped, make a
853 // point of showing the subframe crashed UI. We don't fire the full
854 // `MaybeNotifyCrashed` codepath, as the entire process hasn't crashed on us,
855 // and it may confuse the frontend.
856 mBrowsingContext->BrowserParentDestroyed(
857 this, why == AbnormalShutdown || why == ManagedEndpointDropped);
860 mozilla::ipc::IPCResult BrowserParent::RecvMoveFocus(
861 const bool& aForward, const bool& aForDocumentNavigation) {
862 LOGBROWSERFOCUS(("RecvMoveFocus %p, aForward: %d, aForDocumentNavigation: %d",
863 this, aForward, aForDocumentNavigation));
864 BrowserBridgeParent* bridgeParent = GetBrowserBridgeParent();
865 if (bridgeParent) {
866 mozilla::Unused << bridgeParent->SendMoveFocus(aForward,
867 aForDocumentNavigation);
868 return IPC_OK();
871 RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager();
872 if (fm) {
873 RefPtr<Element> dummy;
875 uint32_t type =
876 aForward
877 ? (aForDocumentNavigation
878 ? static_cast<uint32_t>(
879 nsIFocusManager::MOVEFOCUS_FORWARDDOC)
880 : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARD))
881 : (aForDocumentNavigation
882 ? static_cast<uint32_t>(
883 nsIFocusManager::MOVEFOCUS_BACKWARDDOC)
884 : static_cast<uint32_t>(
885 nsIFocusManager::MOVEFOCUS_BACKWARD));
886 fm->MoveFocus(nullptr, mFrameElement, type, nsIFocusManager::FLAG_BYKEY,
887 getter_AddRefs(dummy));
889 return IPC_OK();
892 mozilla::ipc::IPCResult BrowserParent::RecvDropLinks(
893 nsTArray<nsString>&& aLinks) {
894 nsCOMPtr<nsIBrowser> browser =
895 mFrameElement ? mFrameElement->AsBrowser() : nullptr;
896 if (browser) {
897 // Verify that links have not been modified by the child. If links have
898 // not been modified then it's safe to load those links using the
899 // SystemPrincipal. If they have been modified by web content, then
900 // we use a NullPrincipal which still allows to load web links.
901 bool loadUsingSystemPrincipal = true;
902 if (aLinks.Length() != mVerifyDropLinks.Length()) {
903 loadUsingSystemPrincipal = false;
905 for (uint32_t i = 0; i < aLinks.Length(); i++) {
906 if (loadUsingSystemPrincipal) {
907 if (!aLinks[i].Equals(mVerifyDropLinks[i])) {
908 loadUsingSystemPrincipal = false;
912 mVerifyDropLinks.Clear();
913 nsCOMPtr<nsIPrincipal> triggeringPrincipal;
914 if (loadUsingSystemPrincipal) {
915 triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
916 } else {
917 triggeringPrincipal = NullPrincipal::CreateWithoutOriginAttributes();
919 browser->DropLinks(aLinks, triggeringPrincipal);
921 return IPC_OK();
924 bool BrowserParent::SendLoadRemoteScript(const nsAString& aURL,
925 const bool& aRunInGlobalScope) {
926 if (mCreatingWindow) {
927 mDelayedFrameScripts.AppendElement(
928 FrameScriptInfo(nsString(aURL), aRunInGlobalScope));
929 return true;
932 MOZ_ASSERT(mDelayedFrameScripts.IsEmpty());
933 return PBrowserParent::SendLoadRemoteScript(aURL, aRunInGlobalScope);
936 void BrowserParent::LoadURL(nsDocShellLoadState* aLoadState) {
937 MOZ_ASSERT(aLoadState);
938 MOZ_ASSERT(aLoadState->URI());
939 if (mIsDestroyed) {
940 return;
943 if (mCreatingWindow) {
944 // Don't send the message if the child wants to load its own URL.
945 return;
948 Unused << SendLoadURL(WrapNotNull(aLoadState), GetShowInfo());
951 void BrowserParent::ResumeLoad(uint64_t aPendingSwitchID) {
952 MOZ_ASSERT(aPendingSwitchID != 0);
954 if (NS_WARN_IF(mIsDestroyed)) {
955 return;
958 Unused << SendResumeLoad(aPendingSwitchID, GetShowInfo());
961 void BrowserParent::InitRendering() {
962 if (mRemoteLayerTreeOwner.IsInitialized()) {
963 return;
965 mRemoteLayerTreeOwner.Initialize(this);
967 layers::LayersId layersId = mRemoteLayerTreeOwner.GetLayersId();
968 AddBrowserParentToTable(layersId, this);
970 RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
971 if (frameLoader) {
972 nsIFrame* frame = frameLoader->GetPrimaryFrameOfOwningContent();
973 if (frame) {
974 frame->InvalidateFrame();
978 TextureFactoryIdentifier textureFactoryIdentifier;
979 mRemoteLayerTreeOwner.GetTextureFactoryIdentifier(&textureFactoryIdentifier);
980 Unused << SendInitRendering(textureFactoryIdentifier, layersId,
981 mRemoteLayerTreeOwner.GetCompositorOptions(),
982 mRemoteLayerTreeOwner.IsLayersConnected());
984 RefPtr<nsIWidget> widget = GetTopLevelWidget();
985 if (widget) {
986 ScreenIntMargin safeAreaInsets = widget->GetSafeAreaInsets();
987 Unused << SendSafeAreaInsetsChanged(safeAreaInsets);
990 #if defined(MOZ_WIDGET_ANDROID)
991 MOZ_ASSERT(widget);
993 if (GetBrowsingContext()->IsTopContent()) {
994 Unused << SendDynamicToolbarMaxHeightChanged(
995 widget->GetDynamicToolbarMaxHeight());
997 #endif
1000 bool BrowserParent::AttachWindowRenderer() {
1001 return mRemoteLayerTreeOwner.AttachWindowRenderer();
1004 void BrowserParent::MaybeShowFrame() {
1005 RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
1006 if (!frameLoader) {
1007 return;
1009 frameLoader->MaybeShowFrame();
1012 bool BrowserParent::Show(const OwnerShowInfo& aOwnerInfo) {
1013 mDimensions = aOwnerInfo.size();
1014 if (mIsDestroyed) {
1015 return false;
1018 MOZ_ASSERT(mRemoteLayerTreeOwner.IsInitialized());
1019 if (!mRemoteLayerTreeOwner.AttachWindowRenderer()) {
1020 return false;
1023 mSizeMode = aOwnerInfo.sizeMode();
1024 Unused << SendShow(GetShowInfo(), aOwnerInfo);
1025 return true;
1028 mozilla::ipc::IPCResult BrowserParent::RecvSetDimensions(
1029 mozilla::DimensionRequest aRequest, const double& aScale) {
1030 NS_ENSURE_TRUE(mFrameElement, IPC_OK());
1031 nsCOMPtr<nsIDocShell> docShell = mFrameElement->OwnerDoc()->GetDocShell();
1032 NS_ENSURE_TRUE(docShell, IPC_OK());
1033 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
1034 docShell->GetTreeOwner(getter_AddRefs(treeOwner));
1035 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = do_QueryInterface(treeOwner);
1036 NS_ENSURE_TRUE(treeOwnerAsWin, IPC_OK());
1038 // `BrowserChild` only sends the values to actually be changed, see more
1039 // details in `BrowserChild::SetDimensions()`.
1040 // Note that `BrowserChild::SetDimensions()` may be called before receiving
1041 // our `SendUIResolutionChanged()` call. Therefore, if given each coordinate
1042 // shouldn't be ignored, we need to recompute it if DPI has been changed.
1043 // And also note that don't use `mDefaultScale.scale` here since it may be
1044 // different from the result of `GetWidgetCSSToDeviceScale()`.
1045 // NOTE(emilio): We use GetWidgetCSSToDeviceScale() because the old scale is a
1046 // widget scale, and we only use the current scale to scale up/down the
1047 // relevant values.
1049 CSSToLayoutDeviceScale oldScale((float)aScale);
1050 CSSToLayoutDeviceScale currentScale(
1051 (float)treeOwnerAsWin->GetWidgetCSSToDeviceScale());
1053 if (oldScale != currentScale) {
1054 auto rescaleFunc = [&oldScale, &currentScale](LayoutDeviceIntCoord& aVal) {
1055 aVal = (LayoutDeviceCoord(aVal) / oldScale * currentScale).Rounded();
1057 aRequest.mX.apply(rescaleFunc);
1058 aRequest.mY.apply(rescaleFunc);
1059 aRequest.mWidth.apply(rescaleFunc);
1060 aRequest.mHeight.apply(rescaleFunc);
1063 // treeOwner is the chrome tree owner, but we wan't the content tree owner.
1064 nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = do_GetInterface(treeOwner);
1065 NS_ENSURE_TRUE(webBrowserChrome, IPC_OK());
1066 webBrowserChrome->SetDimensions(std::move(aRequest));
1067 return IPC_OK();
1070 nsresult BrowserParent::UpdatePosition() {
1071 RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
1072 if (!frameLoader) {
1073 return NS_OK;
1075 nsIntRect windowDims;
1076 NS_ENSURE_SUCCESS(frameLoader->GetWindowDimensions(windowDims),
1077 NS_ERROR_FAILURE);
1078 // Avoid updating sizes here.
1079 windowDims.SizeTo(mRect.Size());
1080 UpdateDimensions(windowDims, mDimensions);
1081 return NS_OK;
1084 void BrowserParent::NotifyPositionUpdatedForContentsInPopup() {
1085 if (CanonicalBrowsingContext* bc = GetBrowsingContext()) {
1086 bc->PreOrderWalk([](BrowsingContext* aContext) {
1087 if (WindowGlobalParent* windowGlobalParent =
1088 aContext->Canonical()->GetCurrentWindowGlobal()) {
1089 if (RefPtr<BrowserParent> browserParent =
1090 windowGlobalParent->GetBrowserParent()) {
1091 browserParent->UpdatePosition();
1098 void BrowserParent::UpdateDimensions(const nsIntRect& rect,
1099 const ScreenIntSize& size) {
1100 if (mIsDestroyed) {
1101 return;
1103 nsCOMPtr<nsIWidget> widget = GetWidget();
1104 if (!widget) {
1105 NS_WARNING("No widget found in BrowserParent::UpdateDimensions");
1106 return;
1109 LayoutDeviceIntPoint clientOffset = GetClientOffset();
1110 LayoutDeviceIntPoint chromeOffset = !GetBrowserBridgeParent()
1111 ? -GetChildProcessOffset()
1112 : LayoutDeviceIntPoint();
1114 if (!mUpdatedDimensions || mDimensions != size || !mRect.IsEqualEdges(rect) ||
1115 clientOffset != mClientOffset || chromeOffset != mChromeOffset) {
1116 mUpdatedDimensions = true;
1117 mRect = rect;
1118 mDimensions = size;
1119 mClientOffset = clientOffset;
1120 mChromeOffset = chromeOffset;
1122 Unused << SendUpdateDimensions(GetDimensionInfo());
1123 UpdateNativePointerLockCenter(widget);
1127 DimensionInfo BrowserParent::GetDimensionInfo() {
1128 LayoutDeviceIntRect devicePixelRect = ViewAs<LayoutDevicePixel>(
1129 mRect, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
1130 LayoutDeviceIntSize devicePixelSize = ViewAs<LayoutDevicePixel>(
1131 mDimensions, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
1133 CSSRect unscaledRect = devicePixelRect / mDefaultScale;
1134 CSSSize unscaledSize = devicePixelSize / mDefaultScale;
1135 DimensionInfo di(unscaledRect, unscaledSize, mClientOffset, mChromeOffset);
1136 return di;
1139 void BrowserParent::UpdateNativePointerLockCenter(nsIWidget* aWidget) {
1140 if (!mLockedNativePointer) {
1141 return;
1143 LayoutDeviceIntRect dims(
1144 {0, 0},
1145 ViewAs<LayoutDevicePixel>(
1146 mDimensions, PixelCastJustification::LayoutDeviceIsScreenForTabDims));
1147 aWidget->SetNativePointerLockCenter((dims + mChromeOffset).Center());
1150 void BrowserParent::SizeModeChanged(const nsSizeMode& aSizeMode) {
1151 if (!mIsDestroyed && aSizeMode != mSizeMode) {
1152 mSizeMode = aSizeMode;
1153 Unused << SendSizeModeChanged(aSizeMode);
1157 #if defined(MOZ_WIDGET_ANDROID)
1158 void BrowserParent::DynamicToolbarMaxHeightChanged(ScreenIntCoord aHeight) {
1159 if (!mIsDestroyed) {
1160 Unused << SendDynamicToolbarMaxHeightChanged(aHeight);
1164 void BrowserParent::DynamicToolbarOffsetChanged(ScreenIntCoord aOffset) {
1165 if (!mIsDestroyed) {
1166 Unused << SendDynamicToolbarOffsetChanged(aOffset);
1169 #endif
1171 void BrowserParent::HandleAccessKey(const WidgetKeyboardEvent& aEvent,
1172 nsTArray<uint32_t>& aCharCodes) {
1173 if (!mIsDestroyed) {
1174 // Note that we don't need to mark aEvent is posted to a remote process
1175 // because the event may be dispatched to it as normal keyboard event.
1176 // Therefore, we should use local copy to send it.
1177 WidgetKeyboardEvent localEvent(aEvent);
1178 RequestingAccessKeyEventData::Set(localEvent);
1179 Unused << SendHandleAccessKey(localEvent, aCharCodes);
1183 void BrowserParent::Activate(uint64_t aActionId) {
1184 LOGBROWSERFOCUS(("Activate %p actionid: %" PRIu64, this, aActionId));
1185 if (!mIsDestroyed) {
1186 SetTopLevelWebFocus(this); // Intentionally inside "if"
1187 Unused << SendActivate(aActionId);
1191 void BrowserParent::Deactivate(bool aWindowLowering, uint64_t aActionId) {
1192 LOGBROWSERFOCUS(("Deactivate %p actionid: %" PRIu64, this, aActionId));
1193 if (!aWindowLowering) {
1194 UnsetTopLevelWebFocus(this); // Intentionally outside the next "if"
1196 if (!mIsDestroyed) {
1197 Unused << SendDeactivate(aActionId);
1201 #ifdef ACCESSIBILITY
1202 a11y::PDocAccessibleParent* BrowserParent::AllocPDocAccessibleParent(
1203 PDocAccessibleParent* aParent, const uint64_t&,
1204 const MaybeDiscardedBrowsingContext&) {
1205 // Reference freed in DeallocPDocAccessibleParent.
1206 return a11y::DocAccessibleParent::New().take();
1209 bool BrowserParent::DeallocPDocAccessibleParent(PDocAccessibleParent* aParent) {
1210 // Free reference from AllocPDocAccessibleParent.
1211 static_cast<a11y::DocAccessibleParent*>(aParent)->Release();
1212 return true;
1215 mozilla::ipc::IPCResult BrowserParent::RecvPDocAccessibleConstructor(
1216 PDocAccessibleParent* aDoc, PDocAccessibleParent* aParentDoc,
1217 const uint64_t& aParentID,
1218 const MaybeDiscardedBrowsingContext& aBrowsingContext) {
1219 # if defined(ANDROID)
1220 MonitorAutoLock mal(nsAccessibilityService::GetAndroidMonitor());
1221 # endif
1222 auto doc = static_cast<a11y::DocAccessibleParent*>(aDoc);
1224 // If this tab is already shutting down just mark the new actor as shutdown
1225 // and ignore it. When the tab actor is destroyed it will be too.
1226 if (mIsDestroyed) {
1227 doc->MarkAsShutdown();
1228 return IPC_OK();
1231 if (aParentDoc) {
1232 // Iframe document rendered in the same process as its embedder.
1233 // A document should never directly be the parent of another document.
1234 // There should always be an outer doc accessible child of the outer
1235 // document containing the child.
1236 MOZ_ASSERT(aParentID);
1237 if (!aParentID) {
1238 return IPC_FAIL_NO_REASON(this);
1241 auto parentDoc = static_cast<a11y::DocAccessibleParent*>(aParentDoc);
1242 if (parentDoc->IsShutdown()) {
1243 // This can happen if parentDoc is an OOP iframe, but its embedder has
1244 // been destroyed. (DocAccessibleParent::Destroy destroys any child
1245 // documents.) The OOP iframe (and anything it embeds) will die soon
1246 // anyway, so mark this document as shutdown and ignore it.
1247 doc->MarkAsShutdown();
1248 return IPC_OK();
1251 if (aBrowsingContext) {
1252 doc->SetBrowsingContext(aBrowsingContext.get_canonical());
1255 mozilla::ipc::IPCResult added = parentDoc->AddChildDoc(doc, aParentID);
1256 if (!added) {
1257 # ifdef DEBUG
1258 return added;
1259 # else
1260 return IPC_OK();
1261 # endif
1264 # ifdef XP_WIN
1265 if (a11y::nsWinUtils::IsWindowEmulationStarted()) {
1266 doc->SetEmulatedWindowHandle(parentDoc->GetEmulatedWindowHandle());
1268 # endif
1270 return IPC_OK();
1273 if (aBrowsingContext) {
1274 doc->SetBrowsingContext(aBrowsingContext.get_canonical());
1277 if (auto* bridge = GetBrowserBridgeParent()) {
1278 // Iframe document rendered in a different process to its embedder.
1279 // In this case, we don't get aParentDoc and aParentID.
1280 MOZ_ASSERT(!aParentDoc && !aParentID);
1281 doc->SetTopLevelInContentProcess();
1282 a11y::ProxyCreated(doc);
1283 // It's possible the embedder accessible hasn't been set yet; e.g.
1284 // a hidden iframe. In that case, embedderDoc will be null and this will
1285 // be handled when the embedder is set.
1286 if (a11y::DocAccessibleParent* embedderDoc =
1287 bridge->GetEmbedderAccessibleDoc()) {
1288 mozilla::ipc::IPCResult added = embedderDoc->AddChildDoc(bridge);
1289 if (!added) {
1290 # ifdef DEBUG
1291 return added;
1292 # else
1293 return IPC_OK();
1294 # endif
1297 return IPC_OK();
1298 } else {
1299 // null aParentDoc means this document is at the top level in the child
1300 // process. That means it makes no sense to get an id for an accessible
1301 // that is its parent.
1302 MOZ_ASSERT(!aParentID);
1303 if (aParentID) {
1304 return IPC_FAIL_NO_REASON(this);
1307 if (auto* prevTopLevel = GetTopLevelDocAccessible()) {
1308 // Sometimes, we can get a new top level DocAccessibleParent before the
1309 // old one gets destroyed. The old one will die pretty shortly anyway,
1310 // so just destroy it now. If we don't do this, GetTopLevelDocAccessible()
1311 // might return the wrong document for a short while.
1312 prevTopLevel->Destroy();
1314 doc->SetTopLevel();
1315 a11y::DocManager::RemoteDocAdded(doc);
1316 # ifdef XP_WIN
1317 doc->MaybeInitWindowEmulation();
1318 # endif
1320 return IPC_OK();
1322 #endif
1324 already_AddRefed<PFilePickerParent> BrowserParent::AllocPFilePickerParent(
1325 const nsString& aTitle, const nsIFilePicker::Mode& aMode) {
1326 return MakeAndAddRef<FilePickerParent>(aTitle, aMode);
1329 already_AddRefed<PSessionStoreParent>
1330 BrowserParent::AllocPSessionStoreParent() {
1331 RefPtr<BrowserSessionStore> sessionStore =
1332 BrowserSessionStore::GetOrCreate(mBrowsingContext->Top());
1333 if (!sessionStore) {
1334 return nullptr;
1337 return do_AddRef(new SessionStoreParent(mBrowsingContext, sessionStore));
1340 IPCResult BrowserParent::RecvNewWindowGlobal(
1341 ManagedEndpoint<PWindowGlobalParent>&& aEndpoint,
1342 const WindowGlobalInit& aInit) {
1343 RefPtr<CanonicalBrowsingContext> browsingContext =
1344 CanonicalBrowsingContext::Get(aInit.context().mBrowsingContextId);
1345 if (!browsingContext) {
1346 return IPC_FAIL(this, "Cannot create for missing BrowsingContext");
1348 if (!aInit.principal()) {
1349 return IPC_FAIL(this, "Cannot create without valid principal");
1352 // Ensure we never load a document with a content principal in
1353 // the wrong type of webIsolated process
1354 EnumSet<ContentParent::ValidatePrincipalOptions> validationOptions = {};
1355 nsCOMPtr<nsIURI> docURI = aInit.documentURI();
1356 if (docURI->SchemeIs("about") || docURI->SchemeIs("blob") ||
1357 docURI->SchemeIs("chrome")) {
1358 // XXXckerschb TODO - Do not use SystemPrincipal for:
1359 // Bug 1700639: about:plugins
1360 // Bug 1699385: Remove allowSystem for blobs
1361 // Bug 1698087: chrome://devtools/content/shared/webextension-fallback.html
1362 // chrome reftests, e.g.
1363 // * chrome://reftest/content/writing-mode/ua-style-sheet-button-1a-ref.html
1364 // * chrome://reftest/content/xul-document-load/test003.xhtml
1365 // * chrome://reftest/content/forms/input/text/centering-1.xhtml
1366 validationOptions = {ContentParent::ValidatePrincipalOptions::AllowSystem};
1369 if (!mManager->ValidatePrincipal(aInit.principal(), validationOptions)) {
1370 ContentParent::LogAndAssertFailedPrincipalValidationInfo(aInit.principal(),
1371 __func__);
1374 // Construct our new WindowGlobalParent, bind, and initialize it.
1375 RefPtr<WindowGlobalParent> wgp =
1376 WindowGlobalParent::CreateDisconnected(aInit);
1377 BindPWindowGlobalEndpoint(std::move(aEndpoint), wgp);
1378 wgp->Init();
1379 return IPC_OK();
1382 PVsyncParent* BrowserParent::AllocPVsyncParent() {
1383 MOZ_ASSERT(!mVsyncParent);
1384 mVsyncParent = new VsyncParent();
1385 UpdateVsyncParentVsyncDispatcher();
1386 return mVsyncParent.get();
1389 bool BrowserParent::DeallocPVsyncParent(PVsyncParent* aActor) {
1390 MOZ_ASSERT(aActor);
1391 mVsyncParent = nullptr;
1392 return true;
1395 void BrowserParent::UpdateVsyncParentVsyncDispatcher() {
1396 if (!mVsyncParent) {
1397 return;
1400 if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
1401 RefPtr<VsyncDispatcher> vsyncDispatcher = widget->GetVsyncDispatcher();
1402 if (!vsyncDispatcher) {
1403 vsyncDispatcher = gfxPlatform::GetPlatform()->GetGlobalVsyncDispatcher();
1405 mVsyncParent->UpdateVsyncDispatcher(vsyncDispatcher);
1409 void BrowserParent::MouseEnterIntoWidget() {
1410 if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
1411 // When we mouseenter the remote target, the remote target's cursor should
1412 // become the current cursor. When we mouseexit, we stop.
1413 mRemoteTargetSetsCursor = true;
1414 widget->SetCursor(mCursor);
1415 EventStateManager::ClearCursorSettingManager();
1418 // Mark that we have missed a mouse enter event, so that
1419 // the next mouse event will create a replacement mouse
1420 // enter event and send it to the child.
1421 mIsMouseEnterIntoWidgetEventSuppressed = true;
1424 void BrowserParent::SendRealMouseEvent(WidgetMouseEvent& aEvent) {
1425 if (mIsDestroyed) {
1426 return;
1429 // XXXedgar, if the synthesized mouse events could deliver to the correct
1430 // process directly (see
1431 // https://bugzilla.mozilla.org/show_bug.cgi?id=1549355), we probably don't
1432 // need to check mReason then.
1433 if (aEvent.mReason == WidgetMouseEvent::eReal) {
1434 if (aEvent.mMessage == eMouseExitFromWidget) {
1435 // Since we are leaving this remote target, so don't need to update
1436 // sLastMouseRemoteTarget, and if we are sLastMouseRemoteTarget, reset it
1437 // to null.
1438 BrowserParent::UnsetLastMouseRemoteTarget(this);
1439 } else {
1440 // Last remote target should not be changed without eMouseExitFromWidget.
1441 MOZ_ASSERT_IF(sLastMouseRemoteTarget, sLastMouseRemoteTarget == this);
1442 sLastMouseRemoteTarget = this;
1446 aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
1448 if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
1449 // When we mouseenter the remote target, the remote target's cursor should
1450 // become the current cursor. When we mouseexit, we stop.
1451 if (eMouseEnterIntoWidget == aEvent.mMessage) {
1452 mRemoteTargetSetsCursor = true;
1453 widget->SetCursor(mCursor);
1454 EventStateManager::ClearCursorSettingManager();
1455 } else if (eMouseExitFromWidget == aEvent.mMessage) {
1456 mRemoteTargetSetsCursor = false;
1459 if (!mIsReadyToHandleInputEvents) {
1460 if (eMouseEnterIntoWidget == aEvent.mMessage) {
1461 mIsMouseEnterIntoWidgetEventSuppressed = true;
1462 } else if (eMouseExitFromWidget == aEvent.mMessage) {
1463 mIsMouseEnterIntoWidgetEventSuppressed = false;
1465 return;
1468 ScrollableLayerGuid guid;
1469 uint64_t blockId;
1470 ApzAwareEventRoutingToChild(&guid, &blockId, nullptr);
1472 bool isInputPriorityEventEnabled = Manager()->IsInputPriorityEventEnabled();
1474 if (mIsMouseEnterIntoWidgetEventSuppressed) {
1475 // In the case that the BrowserParent suppressed the eMouseEnterWidget event
1476 // due to its corresponding BrowserChild wasn't ready to handle it, we have
1477 // to resend it when the BrowserChild is ready.
1478 mIsMouseEnterIntoWidgetEventSuppressed = false;
1479 WidgetMouseEvent localEvent(aEvent);
1480 localEvent.mMessage = eMouseEnterIntoWidget;
1481 DebugOnly<bool> ret =
1482 isInputPriorityEventEnabled
1483 ? SendRealMouseEnterExitWidgetEvent(localEvent, guid, blockId)
1484 : SendNormalPriorityRealMouseEnterExitWidgetEvent(localEvent, guid,
1485 blockId);
1486 NS_WARNING_ASSERTION(ret, "SendRealMouseEnterExitWidgetEvent() failed");
1487 MOZ_ASSERT(!ret || localEvent.HasBeenPostedToRemoteProcess());
1490 if (eMouseMove == aEvent.mMessage) {
1491 if (aEvent.mReason == WidgetMouseEvent::eSynthesized) {
1492 DebugOnly<bool> ret =
1493 isInputPriorityEventEnabled
1494 ? SendSynthMouseMoveEvent(aEvent, guid, blockId)
1495 : SendNormalPrioritySynthMouseMoveEvent(aEvent, guid, blockId);
1496 NS_WARNING_ASSERTION(ret, "SendSynthMouseMoveEvent() failed");
1497 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
1498 return;
1501 if (!aEvent.mFlags.mIsSynthesizedForTests) {
1502 DebugOnly<bool> ret =
1503 isInputPriorityEventEnabled
1504 ? SendRealMouseMoveEvent(aEvent, guid, blockId)
1505 : SendNormalPriorityRealMouseMoveEvent(aEvent, guid, blockId);
1506 NS_WARNING_ASSERTION(ret, "SendRealMouseMoveEvent() failed");
1507 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
1508 return;
1511 DebugOnly<bool> ret =
1512 isInputPriorityEventEnabled
1513 ? SendRealMouseMoveEventForTests(aEvent, guid, blockId)
1514 : SendNormalPriorityRealMouseMoveEventForTests(aEvent, guid,
1515 blockId);
1516 NS_WARNING_ASSERTION(ret, "SendRealMouseMoveEventForTests() failed");
1517 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
1518 return;
1521 if (eMouseEnterIntoWidget == aEvent.mMessage ||
1522 eMouseExitFromWidget == aEvent.mMessage) {
1523 DebugOnly<bool> ret =
1524 isInputPriorityEventEnabled
1525 ? SendRealMouseEnterExitWidgetEvent(aEvent, guid, blockId)
1526 : SendNormalPriorityRealMouseEnterExitWidgetEvent(aEvent, guid,
1527 blockId);
1528 NS_WARNING_ASSERTION(ret, "SendRealMouseEnterExitWidgetEvent() failed");
1529 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
1530 return;
1533 DebugOnly<bool> ret =
1534 isInputPriorityEventEnabled
1535 ? SendRealMouseButtonEvent(aEvent, guid, blockId)
1536 : SendNormalPriorityRealMouseButtonEvent(aEvent, guid, blockId);
1537 NS_WARNING_ASSERTION(ret, "SendRealMouseButtonEvent() failed");
1538 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
1541 LayoutDeviceToCSSScale BrowserParent::GetLayoutDeviceToCSSScale() {
1542 Document* doc = (mFrameElement ? mFrameElement->OwnerDoc() : nullptr);
1543 nsPresContext* ctx = (doc ? doc->GetPresContext() : nullptr);
1544 return LayoutDeviceToCSSScale(
1545 ctx ? (float)ctx->AppUnitsPerDevPixel() / AppUnitsPerCSSPixel() : 0.0f);
1548 bool BrowserParent::QueryDropLinksForVerification() {
1549 // Before sending the dragEvent, we query the links being dragged and
1550 // store them on the parent, to make sure the child can not modify links.
1551 nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
1552 if (!dragSession) {
1553 NS_WARNING("No dragSession to query links for verification");
1554 return false;
1557 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
1558 if (!initialDataTransfer) {
1559 NS_WARNING("No initialDataTransfer to query links for verification");
1560 return false;
1563 nsCOMPtr<nsIDroppedLinkHandler> dropHandler =
1564 do_GetService("@mozilla.org/content/dropped-link-handler;1");
1565 if (!dropHandler) {
1566 NS_WARNING("No dropHandler to query links for verification");
1567 return false;
1570 // No more than one drop event can happen simultaneously; reset the link
1571 // verification array and store all links that are being dragged.
1572 mVerifyDropLinks.Clear();
1574 nsTArray<RefPtr<nsIDroppedLinkItem>> droppedLinkItems;
1575 dropHandler->QueryLinks(initialDataTransfer, droppedLinkItems);
1577 // Since the entire event is cancelled if one of the links is invalid,
1578 // we can store all links on the parent side without any prior
1579 // validation checks.
1580 nsresult rv = NS_OK;
1581 for (nsIDroppedLinkItem* item : droppedLinkItems) {
1582 nsString tmp;
1583 rv = item->GetUrl(tmp);
1584 if (NS_FAILED(rv)) {
1585 NS_WARNING("Failed to query url for verification");
1586 break;
1588 mVerifyDropLinks.AppendElement(tmp);
1590 rv = item->GetName(tmp);
1591 if (NS_FAILED(rv)) {
1592 NS_WARNING("Failed to query name for verification");
1593 break;
1595 mVerifyDropLinks.AppendElement(tmp);
1597 rv = item->GetType(tmp);
1598 if (NS_FAILED(rv)) {
1599 NS_WARNING("Failed to query type for verification");
1600 break;
1602 mVerifyDropLinks.AppendElement(tmp);
1604 if (NS_FAILED(rv)) {
1605 mVerifyDropLinks.Clear();
1606 return false;
1608 return true;
1611 void BrowserParent::SendRealDragEvent(WidgetDragEvent& aEvent,
1612 uint32_t aDragAction,
1613 uint32_t aDropEffect,
1614 nsIPrincipal* aPrincipal,
1615 nsIContentSecurityPolicy* aCsp) {
1616 if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
1617 return;
1619 MOZ_ASSERT(!Manager()->IsInputPriorityEventEnabled());
1620 aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
1621 if (aEvent.mMessage == eDrop) {
1622 if (!QueryDropLinksForVerification()) {
1623 return;
1626 DebugOnly<bool> ret = PBrowserParent::SendRealDragEvent(
1627 aEvent, aDragAction, aDropEffect, aPrincipal, aCsp);
1628 NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealDragEvent() failed");
1629 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
1632 void BrowserParent::SendMouseWheelEvent(WidgetWheelEvent& aEvent) {
1633 if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
1634 return;
1637 ScrollableLayerGuid guid;
1638 uint64_t blockId;
1639 ApzAwareEventRoutingToChild(&guid, &blockId, nullptr);
1640 aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
1641 DebugOnly<bool> ret =
1642 Manager()->IsInputPriorityEventEnabled()
1643 ? PBrowserParent::SendMouseWheelEvent(aEvent, guid, blockId)
1644 : PBrowserParent::SendNormalPriorityMouseWheelEvent(aEvent, guid,
1645 blockId);
1647 NS_WARNING_ASSERTION(ret, "PBrowserParent::SendMouseWheelEvent() failed");
1648 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
1651 mozilla::ipc::IPCResult BrowserParent::RecvDispatchWheelEvent(
1652 const mozilla::WidgetWheelEvent& aEvent) {
1653 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1655 nsCOMPtr<nsIWidget> widget = GetWidget();
1656 if (!widget) {
1657 return IPC_OK();
1660 WidgetWheelEvent localEvent(aEvent);
1661 localEvent.mWidget = widget;
1662 localEvent.mRefPoint = TransformChildToParent(localEvent.mRefPoint);
1664 widget->DispatchInputEvent(&localEvent);
1665 return IPC_OK();
1668 mozilla::ipc::IPCResult BrowserParent::RecvDispatchMouseEvent(
1669 const mozilla::WidgetMouseEvent& aEvent) {
1670 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1672 nsCOMPtr<nsIWidget> widget = GetWidget();
1673 if (!widget) {
1674 return IPC_OK();
1677 WidgetMouseEvent localEvent(aEvent);
1678 localEvent.mWidget = widget;
1679 localEvent.mRefPoint = TransformChildToParent(localEvent.mRefPoint);
1681 widget->DispatchInputEvent(&localEvent);
1682 return IPC_OK();
1685 mozilla::ipc::IPCResult BrowserParent::RecvDispatchKeyboardEvent(
1686 const mozilla::WidgetKeyboardEvent& aEvent) {
1687 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1689 nsCOMPtr<nsIWidget> widget = GetWidget();
1690 if (!widget) {
1691 return IPC_OK();
1694 WidgetKeyboardEvent localEvent(aEvent);
1695 localEvent.mWidget = widget;
1696 localEvent.mRefPoint = TransformChildToParent(localEvent.mRefPoint);
1698 widget->DispatchInputEvent(&localEvent);
1699 return IPC_OK();
1702 mozilla::ipc::IPCResult BrowserParent::RecvDispatchTouchEvent(
1703 const mozilla::WidgetTouchEvent& aEvent) {
1704 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1706 nsCOMPtr<nsIWidget> widget = GetWidget();
1707 if (!widget) {
1708 return IPC_OK();
1711 WidgetTouchEvent localEvent(aEvent);
1712 localEvent.mWidget = widget;
1714 for (uint32_t i = 0; i < localEvent.mTouches.Length(); i++) {
1715 localEvent.mTouches[i]->mRefPoint =
1716 TransformChildToParent(localEvent.mTouches[i]->mRefPoint);
1719 widget->DispatchInputEvent(&localEvent);
1720 return IPC_OK();
1723 mozilla::ipc::IPCResult BrowserParent::RecvRequestNativeKeyBindings(
1724 const uint32_t& aType, const WidgetKeyboardEvent& aEvent,
1725 nsTArray<CommandInt>* aCommands) {
1726 MOZ_ASSERT(aCommands);
1727 MOZ_ASSERT(aCommands->IsEmpty());
1729 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1731 NativeKeyBindingsType keyBindingsType =
1732 static_cast<NativeKeyBindingsType>(aType);
1733 switch (keyBindingsType) {
1734 case NativeKeyBindingsType::SingleLineEditor:
1735 case NativeKeyBindingsType::MultiLineEditor:
1736 case NativeKeyBindingsType::RichTextEditor:
1737 break;
1738 default:
1739 return IPC_FAIL(this, "Invalid aType value");
1742 nsCOMPtr<nsIWidget> widget = GetWidget();
1743 if (!widget) {
1744 return IPC_OK();
1747 WidgetKeyboardEvent localEvent(aEvent);
1748 localEvent.mWidget = widget;
1750 if (NS_FAILED(widget->AttachNativeKeyEvent(localEvent))) {
1751 return IPC_OK();
1754 Maybe<WritingMode> writingMode;
1755 if (RefPtr<widget::TextEventDispatcher> dispatcher =
1756 widget->GetTextEventDispatcher()) {
1757 writingMode = dispatcher->MaybeQueryWritingModeAtSelection();
1759 if (localEvent.InitEditCommandsFor(keyBindingsType, writingMode)) {
1760 *aCommands = localEvent.EditCommandsConstRef(keyBindingsType).Clone();
1763 return IPC_OK();
1766 class SynthesizedEventObserver : public nsIObserver {
1767 NS_DECL_ISUPPORTS
1769 public:
1770 SynthesizedEventObserver(BrowserParent* aBrowserParent,
1771 const uint64_t& aObserverId)
1772 : mBrowserParent(aBrowserParent), mObserverId(aObserverId) {
1773 MOZ_ASSERT(mBrowserParent);
1776 NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
1777 const char16_t* aData) override {
1778 if (!mBrowserParent || !mObserverId) {
1779 // We already sent the notification, or we don't actually need to
1780 // send any notification at all.
1781 return NS_OK;
1784 if (mBrowserParent->IsDestroyed()) {
1785 // If this happens it's probably a bug in the test that's triggering this.
1786 NS_WARNING(
1787 "BrowserParent was unexpectedly destroyed during event "
1788 "synthesization!");
1789 } else if (!mBrowserParent->SendNativeSynthesisResponse(
1790 mObserverId, nsCString(aTopic))) {
1791 NS_WARNING("Unable to send native event synthesization response!");
1793 // Null out browserParent to indicate we already sent the response
1794 mBrowserParent = nullptr;
1795 return NS_OK;
1798 private:
1799 virtual ~SynthesizedEventObserver() = default;
1801 RefPtr<BrowserParent> mBrowserParent;
1802 uint64_t mObserverId;
1805 NS_IMPL_ISUPPORTS(SynthesizedEventObserver, nsIObserver)
1807 class MOZ_STACK_CLASS AutoSynthesizedEventResponder {
1808 public:
1809 AutoSynthesizedEventResponder(BrowserParent* aBrowserParent,
1810 const uint64_t& aObserverId, const char* aTopic)
1811 : mObserver(new SynthesizedEventObserver(aBrowserParent, aObserverId)),
1812 mTopic(aTopic) {}
1814 ~AutoSynthesizedEventResponder() {
1815 // This may be a no-op if the observer already sent a response.
1816 mObserver->Observe(nullptr, mTopic, nullptr);
1819 nsIObserver* GetObserver() { return mObserver; }
1821 private:
1822 nsCOMPtr<nsIObserver> mObserver;
1823 const char* mTopic;
1826 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeKeyEvent(
1827 const int32_t& aNativeKeyboardLayout, const int32_t& aNativeKeyCode,
1828 const uint32_t& aModifierFlags, const nsString& aCharacters,
1829 const nsString& aUnmodifiedCharacters, const uint64_t& aObserverId) {
1830 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1832 AutoSynthesizedEventResponder responder(this, aObserverId, "keyevent");
1833 nsCOMPtr<nsIWidget> widget = GetWidget();
1834 if (widget) {
1835 widget->SynthesizeNativeKeyEvent(
1836 aNativeKeyboardLayout, aNativeKeyCode, aModifierFlags, aCharacters,
1837 aUnmodifiedCharacters, responder.GetObserver());
1839 return IPC_OK();
1842 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeMouseEvent(
1843 const LayoutDeviceIntPoint& aPoint, const uint32_t& aNativeMessage,
1844 const int16_t& aButton, const uint32_t& aModifierFlags,
1845 const uint64_t& aObserverId) {
1846 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1848 const uint32_t last =
1849 static_cast<uint32_t>(nsIWidget::NativeMouseMessage::LeaveWindow);
1850 NS_ENSURE_TRUE(aNativeMessage <= last, IPC_FAIL(this, "Bogus message"));
1851 AutoSynthesizedEventResponder responder(this, aObserverId, "mouseevent");
1852 nsCOMPtr<nsIWidget> widget = GetWidget();
1853 if (widget) {
1854 widget->SynthesizeNativeMouseEvent(
1855 aPoint, static_cast<nsIWidget::NativeMouseMessage>(aNativeMessage),
1856 static_cast<mozilla::MouseButton>(aButton),
1857 static_cast<nsIWidget::Modifiers>(aModifierFlags),
1858 responder.GetObserver());
1860 return IPC_OK();
1863 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeMouseMove(
1864 const LayoutDeviceIntPoint& aPoint, const uint64_t& aObserverId) {
1865 // This is used by pointer lock API. So, even if it's not in the automation
1866 // mode, we need to accept the request.
1867 AutoSynthesizedEventResponder responder(this, aObserverId, "mousemove");
1868 nsCOMPtr<nsIWidget> widget = GetWidget();
1869 if (widget) {
1870 widget->SynthesizeNativeMouseMove(aPoint, responder.GetObserver());
1872 return IPC_OK();
1875 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeMouseScrollEvent(
1876 const LayoutDeviceIntPoint& aPoint, const uint32_t& aNativeMessage,
1877 const double& aDeltaX, const double& aDeltaY, const double& aDeltaZ,
1878 const uint32_t& aModifierFlags, const uint32_t& aAdditionalFlags,
1879 const uint64_t& aObserverId) {
1880 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1882 AutoSynthesizedEventResponder responder(this, aObserverId,
1883 "mousescrollevent");
1884 nsCOMPtr<nsIWidget> widget = GetWidget();
1885 if (widget) {
1886 widget->SynthesizeNativeMouseScrollEvent(
1887 aPoint, aNativeMessage, aDeltaX, aDeltaY, aDeltaZ, aModifierFlags,
1888 aAdditionalFlags, responder.GetObserver());
1890 return IPC_OK();
1893 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeTouchPoint(
1894 const uint32_t& aPointerId, const TouchPointerState& aPointerState,
1895 const LayoutDeviceIntPoint& aPoint, const double& aPointerPressure,
1896 const uint32_t& aPointerOrientation, const uint64_t& aObserverId) {
1897 // This is used by DevTools to emulate touch events from mouse events in the
1898 // responsive design mode. Therefore, we should accept the IPC messages even
1899 // if it's not in the automation mode but the browsing context is in RDM pane.
1900 // And the IPC message could be just delayed after closing the responsive
1901 // design mode. Therefore, we shouldn't return IPC_FAIL since doing it makes
1902 // the tab crash.
1903 if (!xpc::IsInAutomation()) {
1904 NS_ENSURE_TRUE(mBrowsingContext, IPC_OK());
1905 NS_ENSURE_TRUE(mBrowsingContext->Top()->GetInRDMPane(), IPC_OK());
1908 AutoSynthesizedEventResponder responder(this, aObserverId, "touchpoint");
1909 nsCOMPtr<nsIWidget> widget = GetWidget();
1910 if (widget) {
1911 widget->SynthesizeNativeTouchPoint(aPointerId, aPointerState, aPoint,
1912 aPointerPressure, aPointerOrientation,
1913 responder.GetObserver());
1915 return IPC_OK();
1918 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeTouchPadPinch(
1919 const TouchpadGesturePhase& aEventPhase, const float& aScale,
1920 const LayoutDeviceIntPoint& aPoint, const int32_t& aModifierFlags) {
1921 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1923 nsCOMPtr<nsIWidget> widget = GetWidget();
1924 if (widget) {
1925 widget->SynthesizeNativeTouchPadPinch(aEventPhase, aScale, aPoint,
1926 aModifierFlags);
1928 return IPC_OK();
1931 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeTouchTap(
1932 const LayoutDeviceIntPoint& aPoint, const bool& aLongTap,
1933 const uint64_t& aObserverId) {
1934 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1936 AutoSynthesizedEventResponder responder(this, aObserverId, "touchtap");
1937 nsCOMPtr<nsIWidget> widget = GetWidget();
1938 if (widget) {
1939 widget->SynthesizeNativeTouchTap(aPoint, aLongTap, responder.GetObserver());
1941 return IPC_OK();
1944 mozilla::ipc::IPCResult BrowserParent::RecvClearNativeTouchSequence(
1945 const uint64_t& aObserverId) {
1946 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1948 AutoSynthesizedEventResponder responder(this, aObserverId, "cleartouch");
1949 nsCOMPtr<nsIWidget> widget = GetWidget();
1950 if (widget) {
1951 widget->ClearNativeTouchSequence(responder.GetObserver());
1953 return IPC_OK();
1956 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativePenInput(
1957 const uint32_t& aPointerId, const TouchPointerState& aPointerState,
1958 const LayoutDeviceIntPoint& aPoint, const double& aPressure,
1959 const uint32_t& aRotation, const int32_t& aTiltX, const int32_t& aTiltY,
1960 const int32_t& aButton, const uint64_t& aObserverId) {
1961 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1963 AutoSynthesizedEventResponder responder(this, aObserverId, "peninput");
1964 nsCOMPtr<nsIWidget> widget = GetWidget();
1965 if (widget) {
1966 widget->SynthesizeNativePenInput(aPointerId, aPointerState, aPoint,
1967 aPressure, aRotation, aTiltX, aTiltY,
1968 aButton, responder.GetObserver());
1970 return IPC_OK();
1973 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeTouchpadDoubleTap(
1974 const LayoutDeviceIntPoint& aPoint, const uint32_t& aModifierFlags) {
1975 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1977 nsCOMPtr<nsIWidget> widget = GetWidget();
1978 if (widget) {
1979 widget->SynthesizeNativeTouchpadDoubleTap(aPoint, aModifierFlags);
1981 return IPC_OK();
1984 mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeTouchpadPan(
1985 const TouchpadGesturePhase& aEventPhase, const LayoutDeviceIntPoint& aPoint,
1986 const double& aDeltaX, const double& aDeltaY, const int32_t& aModifierFlags,
1987 const uint64_t& aObserverId) {
1988 NS_ENSURE_TRUE(xpc::IsInAutomation(), IPC_FAIL(this, "Unexpected event"));
1990 AutoSynthesizedEventResponder responder(this, aObserverId,
1991 "touchpadpanevent");
1993 nsCOMPtr<nsIWidget> widget = GetWidget();
1994 if (widget) {
1995 widget->SynthesizeNativeTouchpadPan(aEventPhase, aPoint, aDeltaX, aDeltaY,
1996 aModifierFlags,
1997 responder.GetObserver());
1999 return IPC_OK();
2002 mozilla::ipc::IPCResult BrowserParent::RecvLockNativePointer() {
2003 if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
2004 mLockedNativePointer = true; // do before updating the center
2005 UpdateNativePointerLockCenter(widget);
2006 widget->LockNativePointer();
2008 return IPC_OK();
2011 void BrowserParent::UnlockNativePointer() {
2012 if (!mLockedNativePointer) {
2013 return;
2015 if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
2016 widget->UnlockNativePointer();
2017 mLockedNativePointer = false;
2021 mozilla::ipc::IPCResult BrowserParent::RecvUnlockNativePointer() {
2022 UnlockNativePointer();
2023 return IPC_OK();
2026 void BrowserParent::SendRealKeyEvent(WidgetKeyboardEvent& aEvent) {
2027 if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
2028 return;
2030 aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
2032 // NOTE: If you call `InitAllEditCommands()` for the other messages too,
2033 // you also need to update
2034 // TextEventDispatcher::DispatchKeyboardEventInternal().
2035 if (aEvent.mMessage == eKeyPress) {
2036 // If current input context is editable, the edit commands are initialized
2037 // by TextEventDispatcher::DispatchKeyboardEventInternal(). Otherwise,
2038 // we need to do it here (they are not necessary for the parent process,
2039 // therefore, we need to do it here for saving the runtime cost).
2040 if (!aEvent.AreAllEditCommandsInitialized()) {
2041 // XXX Is it good thing that the keypress event will be handled in an
2042 // editor even though the user pressed the key combination before the
2043 // focus change has not been completed in the parent process yet or
2044 // focus change will happen? If no, we can stop doing this.
2045 Maybe<WritingMode> writingMode;
2046 if (aEvent.mWidget) {
2047 if (RefPtr<widget::TextEventDispatcher> dispatcher =
2048 aEvent.mWidget->GetTextEventDispatcher()) {
2049 writingMode = dispatcher->MaybeQueryWritingModeAtSelection();
2052 aEvent.InitAllEditCommands(writingMode);
2054 } else {
2055 aEvent.PreventNativeKeyBindings();
2057 SentKeyEventData sendKeyEventData{
2058 aEvent.mKeyCode, aEvent.mCharCode, aEvent.mPseudoCharCode,
2059 aEvent.mKeyNameIndex, aEvent.mCodeNameIndex, aEvent.mModifiers,
2060 nsID::GenerateUUID()};
2061 const bool ok =
2062 Manager()->IsInputPriorityEventEnabled()
2063 ? PBrowserParent::SendRealKeyEvent(aEvent, sendKeyEventData.mUUID)
2064 : PBrowserParent::SendNormalPriorityRealKeyEvent(
2065 aEvent, sendKeyEventData.mUUID);
2067 NS_WARNING_ASSERTION(ok, "PBrowserParent::SendRealKeyEvent() failed");
2068 MOZ_ASSERT(!ok || aEvent.HasBeenPostedToRemoteProcess());
2069 if (ok && aEvent.IsWaitingReplyFromRemoteProcess()) {
2070 mWaitingReplyKeyboardEvents.AppendElement(sendKeyEventData);
2074 void BrowserParent::SendRealTouchEvent(WidgetTouchEvent& aEvent) {
2075 if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
2076 return;
2079 // PresShell::HandleEventInternal adds touches on touch end/cancel. This
2080 // confuses remote content and the panning and zooming logic into thinking
2081 // that the added touches are part of the touchend/cancel, when actually
2082 // they're not.
2083 if (aEvent.mMessage == eTouchEnd || aEvent.mMessage == eTouchCancel) {
2084 aEvent.mTouches.RemoveElementsBy(
2085 [](const auto& touch) { return !touch->mChanged; });
2088 APZData apzData;
2089 ApzAwareEventRoutingToChild(&apzData.guid, &apzData.blockId,
2090 &apzData.apzResponse);
2092 if (mIsDestroyed) {
2093 return;
2096 for (uint32_t i = 0; i < aEvent.mTouches.Length(); i++) {
2097 aEvent.mTouches[i]->mRefPoint =
2098 TransformParentToChild(aEvent.mTouches[i]->mRefPoint);
2101 static uint32_t sConsecutiveTouchMoveCount = 0;
2102 if (aEvent.mMessage == eTouchMove) {
2103 ++sConsecutiveTouchMoveCount;
2104 SendRealTouchMoveEvent(aEvent, apzData, sConsecutiveTouchMoveCount);
2105 return;
2108 sConsecutiveTouchMoveCount = 0;
2109 DebugOnly<bool> ret =
2110 Manager()->IsInputPriorityEventEnabled()
2111 ? PBrowserParent::SendRealTouchEvent(
2112 aEvent, apzData.guid, apzData.blockId, apzData.apzResponse)
2113 : PBrowserParent::SendNormalPriorityRealTouchEvent(
2114 aEvent, apzData.guid, apzData.blockId, apzData.apzResponse);
2116 NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealTouchEvent() failed");
2117 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
2120 void BrowserParent::SendRealTouchMoveEvent(
2121 WidgetTouchEvent& aEvent, APZData& aAPZData,
2122 uint32_t aConsecutiveTouchMoveCount) {
2123 // Touchmove handling is complicated, since IPC compression should be used
2124 // only when there are consecutive touch objects for the same touch on the
2125 // same BrowserParent. IPC compression can be disabled by switching to
2126 // different IPC message.
2127 static bool sIPCMessageType1 = true;
2128 static TabId sLastTargetBrowserParent(0);
2129 static Maybe<APZData> sPreviousAPZData;
2130 // Artificially limit max touch points to 10. That should be in practise
2131 // more than enough.
2132 const uint32_t kMaxTouchMoveIdentifiers = 10;
2133 static Maybe<int32_t> sLastTouchMoveIdentifiers[kMaxTouchMoveIdentifiers];
2135 // Returns true if aIdentifiers contains all the touches in
2136 // sLastTouchMoveIdentifiers.
2137 auto LastTouchMoveIdentifiersContainedIn =
2138 [&](const nsTArray<int32_t>& aIdentifiers) -> bool {
2139 for (Maybe<int32_t>& entry : sLastTouchMoveIdentifiers) {
2140 if (entry.isSome() && !aIdentifiers.Contains(entry.value())) {
2141 return false;
2144 return true;
2147 // Cache touch identifiers in sLastTouchMoveIdentifiers array to be used
2148 // when checking whether compression can be done for the next touchmove.
2149 auto SetLastTouchMoveIdentifiers =
2150 [&](const nsTArray<int32_t>& aIdentifiers) {
2151 for (Maybe<int32_t>& entry : sLastTouchMoveIdentifiers) {
2152 entry.reset();
2155 MOZ_ASSERT(aIdentifiers.Length() <= kMaxTouchMoveIdentifiers);
2156 for (uint32_t j = 0; j < aIdentifiers.Length(); ++j) {
2157 sLastTouchMoveIdentifiers[j].emplace(aIdentifiers[j]);
2161 AutoTArray<int32_t, kMaxTouchMoveIdentifiers> changedTouches;
2162 bool preventCompression = !StaticPrefs::dom_events_compress_touchmove() ||
2163 // Ensure the very first touchmove isn't overridden
2164 // by the second one, so that web pages can get
2165 // accurate coordinates for the first touchmove.
2166 aConsecutiveTouchMoveCount < 3 ||
2167 sPreviousAPZData.isNothing() ||
2168 sPreviousAPZData.value() != aAPZData ||
2169 sLastTargetBrowserParent != GetTabId() ||
2170 aEvent.mTouches.Length() > kMaxTouchMoveIdentifiers;
2172 if (!preventCompression) {
2173 for (RefPtr<Touch>& touch : aEvent.mTouches) {
2174 if (touch->mChanged) {
2175 changedTouches.AppendElement(touch->mIdentifier);
2179 // Prevent compression if the new event has fewer or different touches
2180 // than the old one.
2181 preventCompression = !LastTouchMoveIdentifiersContainedIn(changedTouches);
2184 if (preventCompression) {
2185 sIPCMessageType1 = !sIPCMessageType1;
2188 // Update the last touch move identifiers always, so that when the next
2189 // event comes in, the new identifiers can be compared to the old ones.
2190 // If the pref is disabled, this just does a quick small loop.
2191 SetLastTouchMoveIdentifiers(changedTouches);
2192 sPreviousAPZData.reset();
2193 sPreviousAPZData.emplace(aAPZData);
2194 sLastTargetBrowserParent = GetTabId();
2196 DebugOnly<bool> ret = true;
2197 if (sIPCMessageType1) {
2198 ret =
2199 Manager()->IsInputPriorityEventEnabled()
2200 ? PBrowserParent::SendRealTouchMoveEvent(
2201 aEvent, aAPZData.guid, aAPZData.blockId, aAPZData.apzResponse)
2202 : PBrowserParent::SendNormalPriorityRealTouchMoveEvent(
2203 aEvent, aAPZData.guid, aAPZData.blockId,
2204 aAPZData.apzResponse);
2205 } else {
2206 ret =
2207 Manager()->IsInputPriorityEventEnabled()
2208 ? PBrowserParent::SendRealTouchMoveEvent2(
2209 aEvent, aAPZData.guid, aAPZData.blockId, aAPZData.apzResponse)
2210 : PBrowserParent::SendNormalPriorityRealTouchMoveEvent2(
2211 aEvent, aAPZData.guid, aAPZData.blockId,
2212 aAPZData.apzResponse);
2215 NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealTouchMoveEvent() failed");
2216 MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
2219 bool BrowserParent::SendHandleTap(TapType aType,
2220 const LayoutDevicePoint& aPoint,
2221 Modifiers aModifiers,
2222 const ScrollableLayerGuid& aGuid,
2223 uint64_t aInputBlockId) {
2224 if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
2225 return false;
2227 if ((aType == TapType::eSingleTap || aType == TapType::eSecondTap)) {
2228 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
2229 if (RefPtr<nsFrameLoader> frameLoader = GetFrameLoader()) {
2230 if (RefPtr<Element> element = frameLoader->GetOwnerContent()) {
2231 fm->SetFocus(element, nsIFocusManager::FLAG_BYMOUSE |
2232 nsIFocusManager::FLAG_BYTOUCH |
2233 nsIFocusManager::FLAG_NOSCROLL);
2238 return Manager()->IsInputPriorityEventEnabled()
2239 ? PBrowserParent::SendHandleTap(aType,
2240 TransformParentToChild(aPoint),
2241 aModifiers, aGuid, aInputBlockId)
2242 : PBrowserParent::SendNormalPriorityHandleTap(
2243 aType, TransformParentToChild(aPoint), aModifiers, aGuid,
2244 aInputBlockId);
2247 mozilla::ipc::IPCResult BrowserParent::RecvSyncMessage(
2248 const nsString& aMessage, const ClonedMessageData& aData,
2249 nsTArray<StructuredCloneData>* aRetVal) {
2250 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("BrowserParent::RecvSyncMessage",
2251 OTHER, aMessage);
2252 MMPrinter::Print("BrowserParent::RecvSyncMessage", aMessage, aData);
2254 StructuredCloneData data;
2255 ipc::UnpackClonedMessageData(aData, data);
2257 if (!ReceiveMessage(aMessage, true, &data, aRetVal)) {
2258 return IPC_FAIL_NO_REASON(this);
2260 return IPC_OK();
2263 mozilla::ipc::IPCResult BrowserParent::RecvAsyncMessage(
2264 const nsString& aMessage, const ClonedMessageData& aData) {
2265 AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("BrowserParent::RecvAsyncMessage",
2266 OTHER, aMessage);
2267 MMPrinter::Print("BrowserParent::RecvAsyncMessage", aMessage, aData);
2269 StructuredCloneData data;
2270 ipc::UnpackClonedMessageData(aData, data);
2272 if (!ReceiveMessage(aMessage, false, &data, nullptr)) {
2273 return IPC_FAIL_NO_REASON(this);
2275 return IPC_OK();
2278 mozilla::ipc::IPCResult BrowserParent::RecvSetCursor(
2279 const nsCursor& aCursor, const bool& aHasCustomCursor,
2280 Maybe<BigBuffer>&& aCursorData, const uint32_t& aWidth,
2281 const uint32_t& aHeight, const float& aResolutionX,
2282 const float& aResolutionY, const uint32_t& aStride,
2283 const gfx::SurfaceFormat& aFormat, const uint32_t& aHotspotX,
2284 const uint32_t& aHotspotY, const bool& aForce) {
2285 nsCOMPtr<nsIWidget> widget = GetWidget();
2286 if (!widget) {
2287 return IPC_OK();
2290 if (aForce) {
2291 widget->ClearCachedCursor();
2294 nsCOMPtr<imgIContainer> cursorImage;
2295 if (aHasCustomCursor) {
2296 const bool cursorDataValid = [&] {
2297 if (!aCursorData) {
2298 return false;
2300 auto expectedSize = CheckedInt<uint32_t>(aHeight) * aStride;
2301 if (!expectedSize.isValid() ||
2302 expectedSize.value() != aCursorData->Size()) {
2303 return false;
2305 auto minStride =
2306 CheckedInt<uint32_t>(aWidth) * gfx::BytesPerPixel(aFormat);
2307 if (!minStride.isValid() || aStride < minStride.value()) {
2308 return false;
2310 return true;
2311 }();
2312 if (!cursorDataValid) {
2313 return IPC_FAIL(this, "Invalid custom cursor data");
2315 const gfx::IntSize size(aWidth, aHeight);
2316 RefPtr<gfx::DataSourceSurface> customCursor =
2317 gfx::CreateDataSourceSurfaceFromData(size, aFormat, aCursorData->Data(),
2318 aStride);
2320 RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(customCursor, size);
2321 cursorImage = image::ImageOps::CreateFromDrawable(drawable);
2324 mCursor = nsIWidget::Cursor{aCursor,
2325 std::move(cursorImage),
2326 aHotspotX,
2327 aHotspotY,
2328 {aResolutionX, aResolutionY}};
2329 if (!mRemoteTargetSetsCursor) {
2330 return IPC_OK();
2333 widget->SetCursor(mCursor);
2334 return IPC_OK();
2337 mozilla::ipc::IPCResult BrowserParent::RecvSetLinkStatus(
2338 const nsString& aStatus) {
2339 nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow = GetXULBrowserWindow();
2340 if (!xulBrowserWindow) {
2341 return IPC_OK();
2344 xulBrowserWindow->SetOverLink(aStatus);
2346 return IPC_OK();
2349 mozilla::ipc::IPCResult BrowserParent::RecvShowTooltip(
2350 const uint32_t& aX, const uint32_t& aY, const nsString& aTooltip,
2351 const nsString& aDirection) {
2352 nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow = GetXULBrowserWindow();
2353 if (!xulBrowserWindow) {
2354 return IPC_OK();
2357 // ShowTooltip will end up accessing XULElement properties in JS (specifically
2358 // BoxObject). However, to get it to JS, we need to make sure we're a
2359 // nsFrameLoaderOwner, which implies we're a XULFrameElement. We can then
2360 // safely pass Element into JS.
2361 RefPtr<nsFrameLoaderOwner> flo = do_QueryObject(mFrameElement);
2362 if (!flo) return IPC_OK();
2364 nsCOMPtr<Element> el = do_QueryInterface(flo);
2365 if (!el) return IPC_OK();
2367 if (NS_SUCCEEDED(
2368 xulBrowserWindow->ShowTooltip(aX, aY, aTooltip, aDirection, el))) {
2369 mShowingTooltip = true;
2371 return IPC_OK();
2374 mozilla::ipc::IPCResult BrowserParent::RecvHideTooltip() {
2375 mShowingTooltip = false;
2377 nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow = GetXULBrowserWindow();
2378 if (!xulBrowserWindow) {
2379 return IPC_OK();
2382 xulBrowserWindow->HideTooltip();
2383 return IPC_OK();
2386 mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMEFocus(
2387 const ContentCache& aContentCache, const IMENotification& aIMENotification,
2388 NotifyIMEFocusResolver&& aResolve) {
2389 if (mIsDestroyed) {
2390 return IPC_OK();
2393 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2394 if (!widget) {
2395 aResolve(IMENotificationRequests());
2396 return IPC_OK();
2398 if (NS_WARN_IF(!aContentCache.IsValid())) {
2399 return IPC_FAIL(this, "Invalid content cache data");
2401 mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
2402 IMEStateManager::NotifyIME(aIMENotification, widget, this);
2404 IMENotificationRequests requests;
2405 if (aIMENotification.mMessage == NOTIFY_IME_OF_FOCUS) {
2406 requests = widget->IMENotificationRequestsRef();
2408 aResolve(requests);
2410 return IPC_OK();
2413 mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMETextChange(
2414 const ContentCache& aContentCache,
2415 const IMENotification& aIMENotification) {
2416 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2417 if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
2418 return IPC_OK();
2420 if (NS_WARN_IF(!aContentCache.IsValid())) {
2421 return IPC_FAIL(this, "Invalid content cache data");
2423 mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
2424 mContentCache.MaybeNotifyIME(widget, aIMENotification);
2425 return IPC_OK();
2428 mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMECompositionUpdate(
2429 const ContentCache& aContentCache,
2430 const IMENotification& aIMENotification) {
2431 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2432 if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
2433 return IPC_OK();
2435 if (NS_WARN_IF(!aContentCache.IsValid())) {
2436 return IPC_FAIL(this, "Invalid content cache data");
2438 mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
2439 mContentCache.MaybeNotifyIME(widget, aIMENotification);
2440 return IPC_OK();
2443 mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMESelection(
2444 const ContentCache& aContentCache,
2445 const IMENotification& aIMENotification) {
2446 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2447 if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
2448 return IPC_OK();
2450 if (NS_WARN_IF(!aContentCache.IsValid())) {
2451 return IPC_FAIL(this, "Invalid content cache data");
2453 mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
2454 mContentCache.MaybeNotifyIME(widget, aIMENotification);
2455 return IPC_OK();
2458 mozilla::ipc::IPCResult BrowserParent::RecvUpdateContentCache(
2459 const ContentCache& aContentCache) {
2460 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2461 if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
2462 return IPC_OK();
2464 if (NS_WARN_IF(!aContentCache.IsValid())) {
2465 return IPC_FAIL(this, "Invalid content cache data");
2467 mContentCache.AssignContent(aContentCache, widget);
2468 return IPC_OK();
2471 mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMEMouseButtonEvent(
2472 const IMENotification& aIMENotification, bool* aConsumedByIME) {
2473 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2474 if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
2475 *aConsumedByIME = false;
2476 return IPC_OK();
2478 nsresult rv = IMEStateManager::NotifyIME(aIMENotification, widget, this);
2479 *aConsumedByIME = rv == NS_SUCCESS_EVENT_CONSUMED;
2480 return IPC_OK();
2483 mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMEPositionChange(
2484 const ContentCache& aContentCache,
2485 const IMENotification& aIMENotification) {
2486 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2487 if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
2488 return IPC_OK();
2490 if (NS_WARN_IF(!aContentCache.IsValid())) {
2491 return IPC_FAIL(this, "Invalid content cache data");
2493 mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
2494 mContentCache.MaybeNotifyIME(widget, aIMENotification);
2495 return IPC_OK();
2498 mozilla::ipc::IPCResult BrowserParent::RecvOnEventNeedingAckHandled(
2499 const EventMessage& aMessage, const uint32_t& aCompositionId) {
2500 // This is called when the child process receives WidgetCompositionEvent or
2501 // WidgetSelectionEvent.
2502 // FYI: Don't check if widget is nullptr here because it's more important to
2503 // notify mContentCahce of this than handling something in it.
2504 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
2506 // While calling OnEventNeedingAckHandled(), BrowserParent *might* be
2507 // destroyed since it may send notifications to IME.
2508 RefPtr<BrowserParent> kungFuDeathGrip(this);
2509 mContentCache.OnEventNeedingAckHandled(widget, aMessage, aCompositionId);
2510 return IPC_OK();
2513 mozilla::ipc::IPCResult BrowserParent::RecvRequestFocus(
2514 const bool& aCanRaise, const CallerType aCallerType) {
2515 LOGBROWSERFOCUS(("RecvRequestFocus %p, aCanRaise: %d", this, aCanRaise));
2516 if (BrowserBridgeParent* bridgeParent = GetBrowserBridgeParent()) {
2517 mozilla::Unused << bridgeParent->SendRequestFocus(aCanRaise, aCallerType);
2518 return IPC_OK();
2521 if (!mFrameElement) {
2522 return IPC_OK();
2525 nsContentUtils::RequestFrameFocus(*mFrameElement, aCanRaise, aCallerType);
2526 return IPC_OK();
2529 mozilla::ipc::IPCResult BrowserParent::RecvWheelZoomChange(bool aIncrease) {
2530 RefPtr<BrowsingContext> bc = GetBrowsingContext();
2531 if (!bc) {
2532 return IPC_OK();
2535 bc->Canonical()->DispatchWheelZoomChange(aIncrease);
2536 return IPC_OK();
2539 mozilla::ipc::IPCResult BrowserParent::RecvEnableDisableCommands(
2540 const MaybeDiscarded<BrowsingContext>& aContext, const nsString& aAction,
2541 nsTArray<nsCString>&& aEnabledCommands,
2542 nsTArray<nsCString>&& aDisabledCommands) {
2543 if (aContext.IsNullOrDiscarded()) {
2544 return IPC_OK();
2547 nsCOMPtr<nsIBrowserController> browserController = do_QueryActor(
2548 "Controllers", aContext.get_canonical()->GetCurrentWindowGlobal());
2549 if (browserController) {
2550 browserController->EnableDisableCommands(aAction, aEnabledCommands,
2551 aDisabledCommands);
2554 return IPC_OK();
2557 LayoutDeviceIntPoint BrowserParent::TransformPoint(
2558 const LayoutDeviceIntPoint& aPoint,
2559 const LayoutDeviceToLayoutDeviceMatrix4x4& aMatrix) {
2560 LayoutDevicePoint floatPoint(aPoint);
2561 LayoutDevicePoint floatTransformed = TransformPoint(floatPoint, aMatrix);
2562 // The next line loses precision if an out-of-process iframe
2563 // has been scaled or rotated.
2564 return RoundedToInt(floatTransformed);
2567 LayoutDevicePoint BrowserParent::TransformPoint(
2568 const LayoutDevicePoint& aPoint,
2569 const LayoutDeviceToLayoutDeviceMatrix4x4& aMatrix) {
2570 return aMatrix.TransformPoint(aPoint);
2573 LayoutDeviceIntPoint BrowserParent::TransformParentToChild(
2574 const LayoutDeviceIntPoint& aPoint) {
2575 LayoutDeviceToLayoutDeviceMatrix4x4 matrix =
2576 GetChildToParentConversionMatrix();
2577 if (!matrix.Invert()) {
2578 return LayoutDeviceIntPoint();
2580 auto transformed = UntransformBy(matrix, aPoint);
2581 if (!transformed) {
2582 return LayoutDeviceIntPoint();
2584 return transformed.ref();
2587 LayoutDevicePoint BrowserParent::TransformParentToChild(
2588 const LayoutDevicePoint& aPoint) {
2589 LayoutDeviceToLayoutDeviceMatrix4x4 matrix =
2590 GetChildToParentConversionMatrix();
2591 if (!matrix.Invert()) {
2592 return LayoutDevicePoint();
2594 auto transformed = UntransformBy(matrix, aPoint);
2595 if (!transformed) {
2596 return LayoutDeviceIntPoint();
2598 return transformed.ref();
2601 LayoutDeviceIntPoint BrowserParent::TransformChildToParent(
2602 const LayoutDeviceIntPoint& aPoint) {
2603 return TransformPoint(aPoint, GetChildToParentConversionMatrix());
2606 LayoutDevicePoint BrowserParent::TransformChildToParent(
2607 const LayoutDevicePoint& aPoint) {
2608 return TransformPoint(aPoint, GetChildToParentConversionMatrix());
2611 LayoutDeviceIntRect BrowserParent::TransformChildToParent(
2612 const LayoutDeviceIntRect& aRect) {
2613 LayoutDeviceToLayoutDeviceMatrix4x4 matrix =
2614 GetChildToParentConversionMatrix();
2615 LayoutDeviceRect floatRect(aRect);
2616 // The outcome is not ideal if an out-of-process iframe has been rotated
2617 LayoutDeviceRect floatTransformed = matrix.TransformBounds(floatRect);
2618 // The next line loses precision if an out-of-process iframe
2619 // has been scaled or rotated.
2620 return RoundedToInt(floatTransformed);
2623 LayoutDeviceToLayoutDeviceMatrix4x4
2624 BrowserParent::GetChildToParentConversionMatrix() {
2625 if (mChildToParentConversionMatrix) {
2626 return *mChildToParentConversionMatrix;
2628 LayoutDevicePoint offset(-GetChildProcessOffset());
2629 return LayoutDeviceToLayoutDeviceMatrix4x4::Translation(offset);
2632 void BrowserParent::SetChildToParentConversionMatrix(
2633 const Maybe<LayoutDeviceToLayoutDeviceMatrix4x4>& aMatrix,
2634 const ScreenRect& aRemoteDocumentRect) {
2635 if (mChildToParentConversionMatrix == aMatrix &&
2636 mRemoteDocumentRect.isSome() &&
2637 mRemoteDocumentRect.value() == aRemoteDocumentRect) {
2638 return;
2641 mChildToParentConversionMatrix = aMatrix;
2642 mRemoteDocumentRect = Some(aRemoteDocumentRect);
2643 if (mIsDestroyed) {
2644 return;
2646 mozilla::Unused << SendChildToParentMatrix(ToUnknownMatrix(aMatrix),
2647 aRemoteDocumentRect);
2650 LayoutDeviceIntPoint BrowserParent::GetChildProcessOffset() {
2651 // The "toplevel widget" in child processes is always at position
2652 // 0,0. Map the event coordinates to match that.
2654 LayoutDeviceIntPoint offset(0, 0);
2655 RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
2656 if (!frameLoader) {
2657 return offset;
2659 nsIFrame* targetFrame = frameLoader->GetPrimaryFrameOfOwningContent();
2660 if (!targetFrame) {
2661 return offset;
2664 nsCOMPtr<nsIWidget> widget = GetWidget();
2665 if (!widget) {
2666 return offset;
2669 nsPresContext* presContext = targetFrame->PresContext();
2670 nsIFrame* rootFrame = presContext->PresShell()->GetRootFrame();
2671 nsView* rootView = rootFrame ? rootFrame->GetView() : nullptr;
2672 if (!rootView) {
2673 return offset;
2676 // Note that we don't want to take into account transforms here:
2677 #if 0
2678 nsPoint pt(0, 0);
2679 nsLayoutUtils::TransformPoint(targetFrame, rootFrame, pt);
2680 #endif
2681 // In practice, when transforms are applied to this frameLoader, we currently
2682 // get the wrong results whether we take transforms into account here or not.
2683 // But applying transforms here gives us the wrong results in all
2684 // circumstances when transforms are applied, unless they're purely
2685 // translational. It also gives us the wrong results whenever CSS transitions
2686 // are used to apply transforms, since the offeets aren't updated as the
2687 // transition is animated.
2689 // What we actually need to do is apply the transforms to the coordinates of
2690 // any events we send to the child, and reverse them for any screen
2691 // coordinates that we retrieve from the child.
2693 // TODO: Once we take into account transforms here, set viewportType
2694 // correctly. For now we use Visual as this means we don't apply
2695 // the layout-to-visual transform in TranslateViewToWidget().
2696 ViewportType viewportType = ViewportType::Visual;
2698 nsPoint pt = targetFrame->GetOffsetTo(rootFrame);
2699 return -nsLayoutUtils::TranslateViewToWidget(presContext, rootView, pt,
2700 viewportType, widget);
2703 LayoutDeviceIntPoint BrowserParent::GetClientOffset() {
2704 nsCOMPtr<nsIWidget> widget = GetWidget();
2705 nsCOMPtr<nsIWidget> docWidget = GetDocWidget();
2707 if (widget == docWidget) {
2708 return widget->GetClientOffset();
2711 return (docWidget->GetClientOffset() +
2712 nsLayoutUtils::WidgetToWidgetOffset(widget, docWidget));
2715 void BrowserParent::StopIMEStateManagement() {
2716 if (mIsDestroyed) {
2717 return;
2719 Unused << SendStopIMEStateManagement();
2722 mozilla::ipc::IPCResult BrowserParent::RecvReplyKeyEvent(
2723 const WidgetKeyboardEvent& aEvent, const nsID& aUUID) {
2724 NS_ENSURE_TRUE(mFrameElement, IPC_OK());
2726 // First, verify aEvent is what we've sent to a remote process.
2727 Maybe<size_t> index = [&]() -> Maybe<size_t> {
2728 for (const size_t i : IntegerRange(mWaitingReplyKeyboardEvents.Length())) {
2729 const SentKeyEventData& data = mWaitingReplyKeyboardEvents[i];
2730 if (data.mUUID.Equals(aUUID)) {
2731 if (NS_WARN_IF(data.mKeyCode != aEvent.mKeyCode) ||
2732 NS_WARN_IF(data.mCharCode != aEvent.mCharCode) ||
2733 NS_WARN_IF(data.mPseudoCharCode != aEvent.mPseudoCharCode) ||
2734 NS_WARN_IF(data.mKeyNameIndex != aEvent.mKeyNameIndex) ||
2735 NS_WARN_IF(data.mCodeNameIndex != aEvent.mCodeNameIndex) ||
2736 NS_WARN_IF(data.mModifiers != aEvent.mModifiers)) {
2737 // Got different event data from what we stored before dispatching an
2738 // event with the ID.
2739 return Nothing();
2741 return Some(i);
2744 // No entry found.
2745 return Nothing();
2746 }();
2747 if (MOZ_UNLIKELY(index.isNothing())) {
2748 return IPC_FAIL(this, "Bogus reply keyboard event");
2750 // Don't discard the older keyboard events because the order may be changed if
2751 // the remote process has a event listener which takes too long time and while
2752 // the freezing, user may switch the tab, or if the remote process sends
2753 // synchronous XMLHttpRequest.
2754 mWaitingReplyKeyboardEvents.RemoveElementAt(*index);
2756 // If the event propagation was stopped by the child, it means that the event
2757 // was ignored in the child. In the case, we should ignore it too because the
2758 // focused web app didn't have a chance to prevent its default.
2759 if (aEvent.PropagationStopped()) {
2760 return IPC_OK();
2763 WidgetKeyboardEvent localEvent(aEvent);
2764 localEvent.MarkAsHandledInRemoteProcess();
2766 // Here we convert the WidgetEvent that we received to an Event
2767 // to be able to dispatch it to the <browser> element as the target element.
2768 RefPtr<nsPresContext> presContext =
2769 mFrameElement->OwnerDoc()->GetPresContext();
2770 NS_ENSURE_TRUE(presContext, IPC_OK());
2772 AutoHandlingUserInputStatePusher userInpStatePusher(localEvent.IsTrusted(),
2773 &localEvent);
2775 nsEventStatus status = nsEventStatus_eIgnore;
2777 // Handle access key in this process before dispatching reply event because
2778 // ESM handles it before dispatching the event to the DOM tree.
2779 if (localEvent.mMessage == eKeyPress &&
2780 (localEvent.ModifiersMatchWithAccessKey(AccessKeyType::eChrome) ||
2781 localEvent.ModifiersMatchWithAccessKey(AccessKeyType::eContent))) {
2782 RefPtr<EventStateManager> esm = presContext->EventStateManager();
2783 AutoTArray<uint32_t, 10> accessCharCodes;
2784 localEvent.GetAccessKeyCandidates(accessCharCodes);
2785 if (esm->HandleAccessKey(&localEvent, presContext, accessCharCodes)) {
2786 status = nsEventStatus_eConsumeNoDefault;
2790 RefPtr<Element> frameElement = mFrameElement;
2791 EventDispatcher::Dispatch(frameElement, presContext, &localEvent, nullptr,
2792 &status);
2794 if (!localEvent.DefaultPrevented() &&
2795 !localEvent.mFlags.mIsSynthesizedForTests) {
2796 nsCOMPtr<nsIWidget> widget = GetWidget();
2797 if (widget) {
2798 widget->PostHandleKeyEvent(&localEvent);
2799 localEvent.StopPropagation();
2803 return IPC_OK();
2806 mozilla::ipc::IPCResult BrowserParent::RecvAccessKeyNotHandled(
2807 const WidgetKeyboardEvent& aEvent) {
2808 NS_ENSURE_TRUE(mFrameElement, IPC_OK());
2810 // This is called only when this process had focus and HandleAccessKey
2811 // message was posted to all remote process and each remote process didn't
2812 // execute any content access keys.
2814 if (MOZ_UNLIKELY(aEvent.mMessage != eKeyPress || !aEvent.IsTrusted())) {
2815 return IPC_FAIL(this, "Called with unexpected event");
2818 // If there is no requesting event, the event may have already been handled
2819 // when it's returned from another remote process.
2820 if (MOZ_UNLIKELY(!RequestingAccessKeyEventData::IsSet())) {
2821 return IPC_OK();
2824 // If the event does not match with the one which we requested a remote
2825 // process to handle access key of (that means that we has already requested
2826 // for another key press), we should ignore this call because user focuses
2827 // to the last key press.
2828 if (MOZ_UNLIKELY(!RequestingAccessKeyEventData::Equals(aEvent))) {
2829 return IPC_OK();
2832 RequestingAccessKeyEventData::Clear();
2834 WidgetKeyboardEvent localEvent(aEvent);
2835 localEvent.MarkAsHandledInRemoteProcess();
2836 localEvent.mMessage = eAccessKeyNotFound;
2838 // Here we convert the WidgetEvent that we received to an Event
2839 // to be able to dispatch it to the <browser> element as the target element.
2840 Document* doc = mFrameElement->OwnerDoc();
2841 PresShell* presShell = doc->GetPresShell();
2842 NS_ENSURE_TRUE(presShell, IPC_OK());
2844 if (presShell->CanDispatchEvent()) {
2845 RefPtr<nsPresContext> presContext = presShell->GetPresContext();
2846 NS_ENSURE_TRUE(presContext, IPC_OK());
2848 RefPtr<Element> frameElement = mFrameElement;
2849 EventDispatcher::Dispatch(frameElement, presContext, &localEvent);
2852 return IPC_OK();
2855 mozilla::ipc::IPCResult BrowserParent::RecvRegisterProtocolHandler(
2856 const nsString& aScheme, nsIURI* aHandlerURI, const nsString& aTitle,
2857 nsIURI* aDocURI) {
2858 nsCOMPtr<nsIWebProtocolHandlerRegistrar> registrar =
2859 do_GetService(NS_WEBPROTOCOLHANDLERREGISTRAR_CONTRACTID);
2860 if (registrar) {
2861 registrar->RegisterProtocolHandler(aScheme, aHandlerURI, aTitle, aDocURI,
2862 mFrameElement);
2865 return IPC_OK();
2868 mozilla::ipc::IPCResult BrowserParent::RecvOnStateChange(
2869 const WebProgressData& aWebProgressData, const RequestData& aRequestData,
2870 const uint32_t aStateFlags, const nsresult aStatus,
2871 const Maybe<WebProgressStateChangeData>& aStateChangeData) {
2872 RefPtr<CanonicalBrowsingContext> browsingContext =
2873 BrowsingContextForWebProgress(aWebProgressData);
2874 if (!browsingContext) {
2875 return IPC_OK();
2878 nsCOMPtr<nsIRequest> request;
2879 if (aRequestData.requestURI()) {
2880 request = MakeAndAddRef<RemoteWebProgressRequest>(
2881 aRequestData.requestURI(), aRequestData.originalRequestURI(),
2882 aRequestData.matchedList());
2885 if (aStateChangeData.isSome()) {
2886 if (!browsingContext->IsTopContent()) {
2887 return IPC_FAIL(
2888 this,
2889 "Unexpected WebProgressStateChangeData for non toplevel webProgress");
2892 if (nsCOMPtr<nsIBrowser> browser = GetBrowser()) {
2893 Unused << browser->SetIsNavigating(aStateChangeData->isNavigating());
2894 Unused << browser->SetMayEnableCharacterEncodingMenu(
2895 aStateChangeData->mayEnableCharacterEncodingMenu());
2896 Unused << browser->UpdateForStateChange(aStateChangeData->charset(),
2897 aStateChangeData->documentURI(),
2898 aStateChangeData->contentType());
2902 if (auto* listener = browsingContext->GetWebProgress()) {
2903 listener->OnStateChange(listener, request, aStateFlags, aStatus);
2906 return IPC_OK();
2909 mozilla::ipc::IPCResult BrowserParent::RecvOnProgressChange(
2910 const int32_t aCurTotalProgress, const int32_t aMaxTotalProgress) {
2911 // We only collect progress change notifications for the toplevel
2912 // BrowserParent.
2913 // FIXME: In the future, consider merging in progress change information from
2914 // oop subframes.
2915 if (!GetBrowsingContext()->IsTopContent() ||
2916 !GetBrowsingContext()->GetWebProgress()) {
2917 return IPC_OK();
2920 GetBrowsingContext()->GetWebProgress()->OnProgressChange(
2921 nullptr, nullptr, 0, 0, aCurTotalProgress, aMaxTotalProgress);
2923 return IPC_OK();
2926 mozilla::ipc::IPCResult BrowserParent::RecvOnLocationChange(
2927 const WebProgressData& aWebProgressData, const RequestData& aRequestData,
2928 nsIURI* aLocation, const uint32_t aFlags, const bool aCanGoBack,
2929 const bool aCanGoForward,
2930 const Maybe<WebProgressLocationChangeData>& aLocationChangeData) {
2931 RefPtr<CanonicalBrowsingContext> browsingContext =
2932 BrowsingContextForWebProgress(aWebProgressData);
2933 if (!browsingContext) {
2934 return IPC_OK();
2937 nsCOMPtr<nsIRequest> request;
2938 if (aRequestData.requestURI()) {
2939 request = MakeAndAddRef<RemoteWebProgressRequest>(
2940 aRequestData.requestURI(), aRequestData.originalRequestURI(),
2941 aRequestData.matchedList());
2944 browsingContext->SetCurrentRemoteURI(aLocation);
2946 nsCOMPtr<nsIBrowser> browser = GetBrowser();
2947 if (!mozilla::SessionHistoryInParent() && browser) {
2948 Unused << browser->UpdateWebNavigationForLocationChange(aCanGoBack,
2949 aCanGoForward);
2952 if (aLocationChangeData.isSome()) {
2953 if (!browsingContext->IsTopContent()) {
2954 return IPC_FAIL(this,
2955 "Unexpected WebProgressLocationChangeData for non "
2956 "toplevel webProgress");
2959 if (browser) {
2960 Unused << browser->SetIsNavigating(aLocationChangeData->isNavigating());
2961 Unused << browser->UpdateForLocationChange(
2962 aLocation, aLocationChangeData->charset(),
2963 aLocationChangeData->mayEnableCharacterEncodingMenu(),
2964 aLocationChangeData->documentURI(), aLocationChangeData->title(),
2965 aLocationChangeData->contentPrincipal(),
2966 aLocationChangeData->contentPartitionedPrincipal(),
2967 aLocationChangeData->csp(), aLocationChangeData->referrerInfo(),
2968 aLocationChangeData->isSyntheticDocument(),
2969 aLocationChangeData->requestContextID().isSome(),
2970 aLocationChangeData->requestContextID().valueOr(0),
2971 aLocationChangeData->contentType());
2975 if (auto* listener = browsingContext->GetWebProgress()) {
2976 listener->OnLocationChange(listener, request, aLocation, aFlags);
2979 // Since we've now changed Documents, notify the BrowsingContext that we've
2980 // changed. Ideally we'd just let the BrowsingContext do this when it changes
2981 // the current window global, but that happens before this and we have a lot
2982 // of tests that depend on the specific ordering of messages.
2983 if (browsingContext->IsTopContent() &&
2984 !(aFlags & nsIWebProgressListener::LOCATION_CHANGE_SAME_DOCUMENT)) {
2985 browsingContext->UpdateSecurityState();
2987 return IPC_OK();
2990 mozilla::ipc::IPCResult BrowserParent::RecvOnStatusChange(
2991 const nsString& aMessage) {
2992 // We only collect status change notifications for the toplevel
2993 // BrowserParent.
2994 // FIXME: In the future, consider merging in status change information from
2995 // oop subframes.
2996 if (!GetBrowsingContext()->IsTopContent() ||
2997 !GetBrowsingContext()->GetWebProgress()) {
2998 return IPC_OK();
3001 GetBrowsingContext()->GetWebProgress()->OnStatusChange(nullptr, nullptr,
3002 NS_OK, aMessage.get());
3004 return IPC_OK();
3007 mozilla::ipc::IPCResult BrowserParent::RecvNavigationFinished() {
3008 nsCOMPtr<nsIBrowser> browser =
3009 mFrameElement ? mFrameElement->AsBrowser() : nullptr;
3011 if (browser) {
3012 browser->SetIsNavigating(false);
3015 return IPC_OK();
3018 mozilla::ipc::IPCResult BrowserParent::RecvNotifyContentBlockingEvent(
3019 const uint32_t& aEvent, const RequestData& aRequestData,
3020 const bool aBlocked, const nsACString& aTrackingOrigin,
3021 nsTArray<nsCString>&& aTrackingFullHashes,
3022 const Maybe<
3023 mozilla::ContentBlockingNotifier::StorageAccessPermissionGrantedReason>&
3024 aReason) {
3025 RefPtr<BrowsingContext> bc = GetBrowsingContext();
3027 if (!bc || bc->IsDiscarded()) {
3028 return IPC_OK();
3031 // Get the top-level browsing context.
3032 bc = bc->Top();
3033 RefPtr<dom::WindowGlobalParent> wgp =
3034 bc->Canonical()->GetCurrentWindowGlobal();
3036 // The WindowGlobalParent would be null while running the test
3037 // browser_339445.js. This is unexpected and we will address this in a
3038 // following bug. For now, we first workaround this issue.
3039 if (!wgp) {
3040 return IPC_OK();
3043 nsCOMPtr<nsIRequest> request = MakeAndAddRef<RemoteWebProgressRequest>(
3044 aRequestData.requestURI(), aRequestData.originalRequestURI(),
3045 aRequestData.matchedList());
3047 wgp->NotifyContentBlockingEvent(aEvent, request, aBlocked, aTrackingOrigin,
3048 aTrackingFullHashes, aReason);
3050 return IPC_OK();
3053 already_AddRefed<nsIBrowser> BrowserParent::GetBrowser() {
3054 nsCOMPtr<nsIBrowser> browser;
3055 RefPtr<Element> currentElement = mFrameElement;
3057 // In Responsive Design Mode, mFrameElement will be the <iframe mozbrowser>,
3058 // but we want the <xul:browser> that it is embedded in.
3059 while (currentElement) {
3060 browser = currentElement->AsBrowser();
3061 if (browser) {
3062 break;
3065 BrowsingContext* browsingContext =
3066 currentElement->OwnerDoc()->GetBrowsingContext();
3067 currentElement =
3068 browsingContext ? browsingContext->GetEmbedderElement() : nullptr;
3071 return browser.forget();
3074 already_AddRefed<CanonicalBrowsingContext>
3075 BrowserParent::BrowsingContextForWebProgress(
3076 const WebProgressData& aWebProgressData) {
3077 // Look up the BrowsingContext which this notification was fired for.
3078 if (aWebProgressData.browsingContext().IsNullOrDiscarded()) {
3079 NS_WARNING("WebProgress Ignored: BrowsingContext is null or discarded");
3080 return nullptr;
3082 RefPtr<CanonicalBrowsingContext> browsingContext =
3083 aWebProgressData.browsingContext().get_canonical();
3085 // Double-check that we actually manage this BrowsingContext, and are not
3086 // receiving a malformed or out-of-date request. browsingContext should either
3087 // be the toplevel one managed by this BrowserParent, or embedded within a
3088 // WindowGlobalParent managed by this BrowserParent.
3089 if (browsingContext != mBrowsingContext) {
3090 WindowGlobalParent* embedder = browsingContext->GetParentWindowContext();
3091 if (!embedder || embedder->GetBrowserParent() != this) {
3092 NS_WARNING("WebProgress Ignored: wrong embedder process");
3093 return nullptr;
3097 // The current process for this BrowsingContext may have changed since the
3098 // notification was fired. Don't fire events for it anymore, as ownership of
3099 // the BrowsingContext has been moved elsewhere.
3100 if (RefPtr<WindowGlobalParent> current =
3101 browsingContext->GetCurrentWindowGlobal();
3102 current && current->GetBrowserParent() != this) {
3103 NS_WARNING("WebProgress Ignored: no longer current window global");
3104 return nullptr;
3107 if (RefPtr<BrowsingContextWebProgress> progress =
3108 browsingContext->GetWebProgress()) {
3109 progress->SetLoadType(aWebProgressData.loadType());
3112 return browsingContext.forget();
3115 mozilla::ipc::IPCResult BrowserParent::RecvIntrinsicSizeOrRatioChanged(
3116 const Maybe<IntrinsicSize>& aIntrinsicSize,
3117 const Maybe<AspectRatio>& aIntrinsicRatio) {
3118 BrowserBridgeParent* bridge = GetBrowserBridgeParent();
3119 if (!bridge || !bridge->CanSend()) {
3120 return IPC_OK();
3123 Unused << bridge->SendIntrinsicSizeOrRatioChanged(aIntrinsicSize,
3124 aIntrinsicRatio);
3126 return IPC_OK();
3129 mozilla::ipc::IPCResult BrowserParent::RecvImageLoadComplete(
3130 const nsresult& aResult) {
3131 BrowserBridgeParent* bridge = GetBrowserBridgeParent();
3132 if (!bridge || !bridge->CanSend()) {
3133 return IPC_OK();
3136 Unused << bridge->SendImageLoadComplete(aResult);
3138 return IPC_OK();
3141 bool BrowserParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent) {
3142 nsCOMPtr<nsIWidget> textInputHandlingWidget = GetTextInputHandlingWidget();
3143 if (!textInputHandlingWidget) {
3144 return true;
3146 if (!mContentCache.HandleQueryContentEvent(aEvent, textInputHandlingWidget) ||
3147 NS_WARN_IF(aEvent.Failed())) {
3148 return true;
3150 switch (aEvent.mMessage) {
3151 case eQueryTextRect:
3152 case eQueryCaretRect:
3153 case eQueryEditorRect: {
3154 nsCOMPtr<nsIWidget> browserWidget = GetWidget();
3155 if (browserWidget != textInputHandlingWidget) {
3156 aEvent.mReply->mRect += nsLayoutUtils::WidgetToWidgetOffset(
3157 browserWidget, textInputHandlingWidget);
3159 aEvent.mReply->mRect = TransformChildToParent(aEvent.mReply->mRect);
3160 break;
3162 default:
3163 break;
3165 return true;
3168 bool BrowserParent::SendCompositionEvent(WidgetCompositionEvent& aEvent,
3169 uint32_t aCompositionId) {
3170 if (mIsDestroyed) {
3171 return false;
3174 // When the composition is handled in a remote process, we need to handle
3175 // commit/cancel result for composition with the composition ID to avoid
3176 // to abort newer composition. Therefore, we need to let the remote process
3177 // know the composition ID.
3178 MOZ_ASSERT(aCompositionId != 0);
3179 aEvent.mCompositionId = aCompositionId;
3181 if (!mContentCache.OnCompositionEvent(aEvent)) {
3182 return true;
3185 bool ret = Manager()->IsInputPriorityEventEnabled()
3186 ? PBrowserParent::SendCompositionEvent(aEvent)
3187 : PBrowserParent::SendNormalPriorityCompositionEvent(aEvent);
3188 if (NS_WARN_IF(!ret)) {
3189 return false;
3191 MOZ_ASSERT(aEvent.HasBeenPostedToRemoteProcess());
3192 return true;
3195 bool BrowserParent::SendSelectionEvent(WidgetSelectionEvent& aEvent) {
3196 if (mIsDestroyed) {
3197 return false;
3199 nsCOMPtr<nsIWidget> widget = GetWidget();
3200 if (!widget) {
3201 return true;
3203 mContentCache.OnSelectionEvent(aEvent);
3204 bool ret = Manager()->IsInputPriorityEventEnabled()
3205 ? PBrowserParent::SendSelectionEvent(aEvent)
3206 : PBrowserParent::SendNormalPrioritySelectionEvent(aEvent);
3207 if (NS_WARN_IF(!ret)) {
3208 return false;
3210 MOZ_ASSERT(aEvent.HasBeenPostedToRemoteProcess());
3211 aEvent.mSucceeded = true;
3212 return true;
3215 bool BrowserParent::SendInsertText(const nsString& aStringToInsert) {
3216 if (mIsDestroyed) {
3217 return false;
3219 return Manager()->IsInputPriorityEventEnabled()
3220 ? PBrowserParent::SendInsertText(aStringToInsert)
3221 : PBrowserParent::SendNormalPriorityInsertText(aStringToInsert);
3224 bool BrowserParent::SendPasteTransferable(
3225 IPCTransferableData&& aTransferableData, const bool& aIsPrivateData,
3226 nsIPrincipal* aRequestingPrincipal,
3227 const nsContentPolicyType& aContentPolicyType) {
3228 return PBrowserParent::SendPasteTransferable(
3229 std::move(aTransferableData), aIsPrivateData, aRequestingPrincipal,
3230 aContentPolicyType);
3233 /* static */
3234 void BrowserParent::SetTopLevelWebFocus(BrowserParent* aBrowserParent) {
3235 BrowserParent* old = GetFocused();
3236 if (aBrowserParent && !aBrowserParent->GetBrowserBridgeParent()) {
3237 // top-level Web content
3238 sTopLevelWebFocus = aBrowserParent;
3239 BrowserParent* bp = UpdateFocus();
3240 if (old != bp) {
3241 LOGBROWSERFOCUS(
3242 ("SetTopLevelWebFocus updated focus; old: %p, new: %p", old, bp));
3243 IMEStateManager::OnFocusMovedBetweenBrowsers(old, bp);
3248 /* static */
3249 void BrowserParent::UnsetTopLevelWebFocus(BrowserParent* aBrowserParent) {
3250 BrowserParent* old = GetFocused();
3251 if (sTopLevelWebFocus == aBrowserParent) {
3252 // top-level Web content
3253 sTopLevelWebFocus = nullptr;
3254 sFocus = nullptr;
3255 if (old) {
3256 LOGBROWSERFOCUS(
3257 ("UnsetTopLevelWebFocus moved focus to chrome; old: %p", old));
3258 IMEStateManager::OnFocusMovedBetweenBrowsers(old, nullptr);
3263 /* static */
3264 void BrowserParent::UpdateFocusFromBrowsingContext() {
3265 BrowserParent* old = GetFocused();
3266 BrowserParent* bp = UpdateFocus();
3267 if (old != bp) {
3268 LOGBROWSERFOCUS(
3269 ("UpdateFocusFromBrowsingContext updated focus; old: %p, new: %p", old,
3270 bp));
3271 IMEStateManager::OnFocusMovedBetweenBrowsers(old, bp);
3275 /* static */
3276 BrowserParent* BrowserParent::UpdateFocus() {
3277 if (!sTopLevelWebFocus) {
3278 sFocus = nullptr;
3279 return nullptr;
3281 nsFocusManager* fm = nsFocusManager::GetFocusManager();
3282 if (fm) {
3283 BrowsingContext* bc = fm->GetFocusedBrowsingContextInChrome();
3284 if (bc) {
3285 BrowsingContext* top = bc->Top();
3286 MOZ_ASSERT(top, "Should always have a top BrowsingContext.");
3287 CanonicalBrowsingContext* canonicalTop = top->Canonical();
3288 MOZ_ASSERT(canonicalTop,
3289 "Casting to canonical should always be possible in the parent "
3290 "process (top case).");
3291 WindowGlobalParent* globalTop = canonicalTop->GetCurrentWindowGlobal();
3292 if (globalTop) {
3293 RefPtr<BrowserParent> globalTopParent = globalTop->GetBrowserParent();
3294 if (sTopLevelWebFocus == globalTopParent) {
3295 CanonicalBrowsingContext* canonical = bc->Canonical();
3296 MOZ_ASSERT(
3297 canonical,
3298 "Casting to canonical should always be possible in the parent "
3299 "process.");
3300 WindowGlobalParent* global = canonical->GetCurrentWindowGlobal();
3301 if (global) {
3302 RefPtr<BrowserParent> parent = global->GetBrowserParent();
3303 sFocus = parent;
3304 return sFocus;
3306 LOGBROWSERFOCUS(
3307 ("Focused BrowsingContext did not have WindowGlobalParent."));
3309 } else {
3310 LOGBROWSERFOCUS(
3311 ("Top-level BrowsingContext did not have WindowGlobalParent."));
3315 sFocus = sTopLevelWebFocus;
3316 return sFocus;
3319 /* static */
3320 void BrowserParent::UnsetTopLevelWebFocusAll() {
3321 if (sTopLevelWebFocus) {
3322 UnsetTopLevelWebFocus(sTopLevelWebFocus);
3326 /* static */
3327 void BrowserParent::UnsetLastMouseRemoteTarget(BrowserParent* aBrowserParent) {
3328 if (sLastMouseRemoteTarget == aBrowserParent) {
3329 sLastMouseRemoteTarget = nullptr;
3333 mozilla::ipc::IPCResult BrowserParent::RecvRequestIMEToCommitComposition(
3334 const bool& aCancel, const uint32_t& aCompositionId, bool* aIsCommitted,
3335 nsString* aCommittedString) {
3336 nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
3337 if (!widget) {
3338 *aIsCommitted = false;
3339 return IPC_OK();
3342 *aIsCommitted = mContentCache.RequestIMEToCommitComposition(
3343 widget, aCancel, aCompositionId, *aCommittedString);
3344 return IPC_OK();
3347 mozilla::ipc::IPCResult BrowserParent::RecvGetInputContext(
3348 widget::IMEState* aState) {
3349 nsCOMPtr<nsIWidget> widget = GetWidget();
3350 if (!widget) {
3351 *aState = widget::IMEState(IMEEnabled::Disabled,
3352 IMEState::OPEN_STATE_NOT_SUPPORTED);
3353 return IPC_OK();
3356 *aState = widget->GetInputContext().mIMEState;
3357 return IPC_OK();
3360 mozilla::ipc::IPCResult BrowserParent::RecvSetInputContext(
3361 const InputContext& aContext, const InputContextAction& aAction) {
3362 IMEStateManager::SetInputContextForChildProcess(this, aContext, aAction);
3363 return IPC_OK();
3366 bool BrowserParent::ReceiveMessage(const nsString& aMessage, bool aSync,
3367 StructuredCloneData* aData,
3368 nsTArray<StructuredCloneData>* aRetVal) {
3369 // If we're for an oop iframe, don't deliver messages to the wrong place.
3370 if (mBrowserBridgeParent) {
3371 return true;
3374 RefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
3375 if (frameLoader && frameLoader->GetFrameMessageManager()) {
3376 RefPtr<nsFrameMessageManager> manager =
3377 frameLoader->GetFrameMessageManager();
3379 manager->ReceiveMessage(mFrameElement, frameLoader, aMessage, aSync, aData,
3380 aRetVal, IgnoreErrors());
3382 return true;
3385 // nsIAuthPromptProvider
3387 // This method is largely copied from nsDocShell::GetAuthPrompt
3388 NS_IMETHODIMP
3389 BrowserParent::GetAuthPrompt(uint32_t aPromptReason, const nsIID& iid,
3390 void** aResult) {
3391 // we're either allowing auth, or it's a proxy request
3392 nsresult rv;
3393 nsCOMPtr<nsIPromptFactory> wwatch =
3394 do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
3395 NS_ENSURE_SUCCESS(rv, rv);
3397 nsCOMPtr<nsPIDOMWindowOuter> window;
3398 RefPtr<Element> frame = mFrameElement;
3399 if (frame) window = frame->OwnerDoc()->GetWindow();
3401 // Get an auth prompter for our window so that the parenting
3402 // of the dialogs works as it should when using tabs.
3403 nsCOMPtr<nsISupports> prompt;
3404 rv = wwatch->GetPrompt(window, iid, getter_AddRefs(prompt));
3405 NS_ENSURE_SUCCESS(rv, rv);
3407 nsCOMPtr<nsILoginManagerAuthPrompter> prompter = do_QueryInterface(prompt);
3408 if (prompter) {
3409 prompter->SetBrowser(mFrameElement);
3412 *aResult = prompt.forget().take();
3413 return NS_OK;
3416 already_AddRefed<PColorPickerParent> BrowserParent::AllocPColorPickerParent(
3417 const nsString& aTitle, const nsString& aInitialColor,
3418 const nsTArray<nsString>& aDefaultColors) {
3419 return MakeAndAddRef<ColorPickerParent>(aTitle, aInitialColor,
3420 aDefaultColors);
3423 already_AddRefed<nsFrameLoader> BrowserParent::GetFrameLoader(
3424 bool aUseCachedFrameLoaderAfterDestroy) const {
3425 if (mIsDestroyed && !aUseCachedFrameLoaderAfterDestroy) {
3426 return nullptr;
3429 if (mFrameLoader) {
3430 RefPtr<nsFrameLoader> fl = mFrameLoader;
3431 return fl.forget();
3433 RefPtr<Element> frameElement(mFrameElement);
3434 RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(frameElement);
3435 return frameLoaderOwner ? frameLoaderOwner->GetFrameLoader() : nullptr;
3438 void BrowserParent::TryCacheDPIAndScale() {
3439 if (mDPI > 0) {
3440 return;
3443 const auto oldDefaultScale = mDefaultScale;
3444 nsCOMPtr<nsIWidget> widget = GetWidget();
3445 mDPI = widget ? widget->GetDPI() : nsIWidget::GetFallbackDPI();
3446 mRounding = widget ? widget->RoundsWidgetCoordinatesTo() : 1;
3447 mDefaultScale =
3448 widget ? widget->GetDefaultScale() : nsIWidget::GetFallbackDefaultScale();
3450 if (mDefaultScale != oldDefaultScale) {
3451 // The change of the default scale factor will affect the child dimensions
3452 // so we need to invalidate it.
3453 mUpdatedDimensions = false;
3457 void BrowserParent::ApzAwareEventRoutingToChild(
3458 ScrollableLayerGuid* aOutTargetGuid, uint64_t* aOutInputBlockId,
3459 nsEventStatus* aOutApzResponse) {
3460 // Let the widget know that the event will be sent to the child process,
3461 // which will (hopefully) send a confirmation notice back to APZ.
3462 // Do this even if APZ is off since we need it for swipe gesture support on
3463 // OS X without APZ.
3464 InputAPZContext::SetRoutedToChildProcess();
3466 if (AsyncPanZoomEnabled()) {
3467 if (aOutTargetGuid) {
3468 *aOutTargetGuid = InputAPZContext::GetTargetLayerGuid();
3470 // There may be cases where the APZ hit-testing code came to a different
3471 // conclusion than the main-thread hit-testing code as to where the event
3472 // is destined. In such cases the layersId of the APZ result may not match
3473 // the layersId of this RemoteLayerTreeOwner. In such cases the
3474 // main-thread hit- testing code "wins" so we need to update the guid to
3475 // reflect this.
3476 if (mRemoteLayerTreeOwner.IsInitialized()) {
3477 if (aOutTargetGuid->mLayersId != mRemoteLayerTreeOwner.GetLayersId()) {
3478 *aOutTargetGuid =
3479 ScrollableLayerGuid(mRemoteLayerTreeOwner.GetLayersId(), 0,
3480 ScrollableLayerGuid::NULL_SCROLL_ID);
3484 if (aOutInputBlockId) {
3485 *aOutInputBlockId = InputAPZContext::GetInputBlockId();
3487 if (aOutApzResponse) {
3488 *aOutApzResponse = InputAPZContext::GetApzResponse();
3490 // We can get here without there being an InputAPZContext on the stack
3491 // if a non-native event synthesization function (such as
3492 // nsIDOMWindowUtils.sendTouchEvent()) was used in the parent process to
3493 // synthesize an event that's targeting a content process. Such events do
3494 // not go through APZ. Without an InputAPZContext on the stack we pick up
3495 // the default value "eSentinel" which cannot be sent over IPC, so replace
3496 // it with "eIgnore" instead, which what APZ uses when it ignores an
3497 // event. If a caller needs the ability to synthesize a event with a
3498 // different APZ response, a native event synthesization function (such as
3499 // sendNativeTouchPoint()) can be used.
3500 if (*aOutApzResponse == nsEventStatus_eSentinel) {
3501 *aOutApzResponse = nsEventStatus_eIgnore;
3504 } else {
3505 if (aOutInputBlockId) {
3506 *aOutInputBlockId = 0;
3508 if (aOutApzResponse) {
3509 *aOutApzResponse = nsEventStatus_eIgnore;
3514 mozilla::ipc::IPCResult BrowserParent::RecvRespondStartSwipeEvent(
3515 const uint64_t& aInputBlockId, const bool& aStartSwipe) {
3516 if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
3517 widget->ReportSwipeStarted(aInputBlockId, aStartSwipe);
3519 return IPC_OK();
3522 bool BrowserParent::GetDocShellIsActive() {
3523 return mBrowsingContext && mBrowsingContext->IsActive();
3526 bool BrowserParent::GetHasPresented() { return mHasPresented; }
3528 bool BrowserParent::GetHasLayers() { return mHasLayers; }
3530 bool BrowserParent::GetRenderLayers() { return mRenderLayers; }
3532 void BrowserParent::SetRenderLayers(bool aEnabled) {
3533 if (aEnabled == mRenderLayers) {
3534 return;
3537 // Preserve layers means that attempts to stop rendering layers
3538 // will be ignored.
3539 if (!aEnabled && mIsPreservingLayers) {
3540 return;
3543 mRenderLayers = aEnabled;
3545 SetRenderLayersInternal(aEnabled);
3548 void BrowserParent::SetRenderLayersInternal(bool aEnabled) {
3549 Unused << SendRenderLayers(aEnabled);
3551 // Ask the child to repaint/unload layers using the PHangMonitor
3552 // channel/thread (which may be less congested).
3553 if (aEnabled) {
3554 Manager()->PaintTabWhileInterruptingJS(this);
3555 } else {
3556 Manager()->UnloadLayersWhileInterruptingJS(this);
3560 bool BrowserParent::GetPriorityHint() { return mPriorityHint; }
3562 void BrowserParent::SetPriorityHint(bool aPriorityHint) {
3563 mPriorityHint = aPriorityHint;
3564 RecomputeProcessPriority();
3567 void BrowserParent::RecomputeProcessPriority() {
3568 auto* bc = GetBrowsingContext();
3569 ProcessPriorityManager::BrowserPriorityChanged(
3570 bc, bc->IsActive() || mPriorityHint);
3573 void BrowserParent::PreserveLayers(bool aPreserveLayers) {
3574 if (mIsPreservingLayers == aPreserveLayers) {
3575 return;
3577 mIsPreservingLayers = aPreserveLayers;
3578 Unused << SendPreserveLayers(aPreserveLayers);
3581 void BrowserParent::NotifyResolutionChanged() {
3582 if (mIsDestroyed) {
3583 return;
3585 // TryCacheDPIAndScale()'s cache is keyed off of
3586 // mDPI being greater than 0, so this invalidates it.
3587 mDPI = -1;
3588 TryCacheDPIAndScale();
3589 // If mDPI was set to -1 to invalidate it and then TryCacheDPIAndScale
3590 // fails to cache the values, then mDefaultScale.scale might be invalid.
3591 // We don't want to send that value to content. Just send -1 for it too in
3592 // that case.
3593 Unused << SendUIResolutionChanged(mDPI, mRounding,
3594 mDPI < 0 ? -1.0 : mDefaultScale.scale);
3597 bool BrowserParent::CanCancelContentJS(
3598 nsIRemoteTab::NavigationType aNavigationType, int32_t aNavigationIndex,
3599 nsIURI* aNavigationURI) const {
3600 // Pre-checking if we can cancel content js in the parent is only
3601 // supported when session history in the parent is enabled.
3602 if (!mozilla::SessionHistoryInParent()) {
3603 // If session history in the parent isn't enabled, this check will
3604 // be fully done in BrowserChild::CanCancelContentJS
3605 return true;
3608 nsCOMPtr<nsISHistory> history = mBrowsingContext->GetSessionHistory();
3610 if (!history) {
3611 // If there is no history we can't possibly know if it's ok to
3612 // cancel content js.
3613 return false;
3616 int32_t current;
3617 NS_ENSURE_SUCCESS(history->GetIndex(&current), false);
3619 if (current == -1) {
3620 // This tab has no history! Just return.
3621 return false;
3624 nsCOMPtr<nsISHEntry> entry;
3625 NS_ENSURE_SUCCESS(history->GetEntryAtIndex(current, getter_AddRefs(entry)),
3626 false);
3628 nsCOMPtr<nsIURI> currentURI = entry->GetURI();
3629 if (!currentURI->SchemeIs("http") && !currentURI->SchemeIs("https") &&
3630 !currentURI->SchemeIs("file")) {
3631 // Only cancel content JS for http(s) and file URIs. Other URIs are probably
3632 // internal and we should just let them run to completion.
3633 return false;
3636 if (aNavigationType == nsIRemoteTab::NAVIGATE_BACK) {
3637 aNavigationIndex = current - 1;
3638 } else if (aNavigationType == nsIRemoteTab::NAVIGATE_FORWARD) {
3639 aNavigationIndex = current + 1;
3640 } else if (aNavigationType == nsIRemoteTab::NAVIGATE_URL) {
3641 if (!aNavigationURI) {
3642 return false;
3645 if (aNavigationURI->SchemeIs("javascript")) {
3646 // "javascript:" URIs don't (necessarily) trigger navigation to a
3647 // different page, so don't allow the current page's JS to terminate.
3648 return false;
3651 // If navigating directly to a URL (e.g. via hitting Enter in the location
3652 // bar), then we can cancel anytime the next URL is different from the
3653 // current, *excluding* the ref ("#").
3654 bool equals;
3655 NS_ENSURE_SUCCESS(currentURI->EqualsExceptRef(aNavigationURI, &equals),
3656 false);
3657 return !equals;
3659 // Note: aNavigationType may also be NAVIGATE_INDEX, in which case we don't
3660 // need to do anything special.
3662 int32_t delta = aNavigationIndex > current ? 1 : -1;
3663 for (int32_t i = current + delta; i != aNavigationIndex + delta; i += delta) {
3664 nsCOMPtr<nsISHEntry> nextEntry;
3665 // If `i` happens to be negative, this call will fail (which is what we
3666 // would want to happen).
3667 NS_ENSURE_SUCCESS(history->GetEntryAtIndex(i, getter_AddRefs(nextEntry)),
3668 false);
3670 nsCOMPtr<nsISHEntry> laterEntry = delta == 1 ? nextEntry : entry;
3671 nsCOMPtr<nsIURI> thisURI = entry->GetURI();
3672 nsCOMPtr<nsIURI> nextURI = nextEntry->GetURI();
3674 // If we changed origin and the load wasn't in a subframe, we know it was
3675 // a full document load, so we can cancel the content JS safely.
3676 if (!laterEntry->GetIsSubFrame()) {
3677 nsAutoCString thisHost;
3678 NS_ENSURE_SUCCESS(thisURI->GetPrePath(thisHost), false);
3680 nsAutoCString nextHost;
3681 NS_ENSURE_SUCCESS(nextURI->GetPrePath(nextHost), false);
3683 if (!thisHost.Equals(nextHost)) {
3684 return true;
3688 entry = nextEntry;
3691 return false;
3694 void BrowserParent::SuppressDisplayport(bool aEnabled) {
3695 if (IsDestroyed()) {
3696 return;
3699 #ifdef DEBUG
3700 if (aEnabled) {
3701 mActiveSupressDisplayportCount++;
3702 } else {
3703 mActiveSupressDisplayportCount--;
3705 MOZ_ASSERT(mActiveSupressDisplayportCount >= 0);
3706 #endif
3708 Unused << SendSuppressDisplayport(aEnabled);
3711 void BrowserParent::NavigateByKey(bool aForward, bool aForDocumentNavigation) {
3712 Unused << SendNavigateByKey(aForward, aForDocumentNavigation);
3715 void BrowserParent::LayerTreeUpdate(bool aActive) {
3716 if (NS_WARN_IF(mHasLayers == aActive)) {
3717 return;
3719 mHasPresented |= aActive;
3720 mHasLayers = aActive;
3721 if (GetBrowserBridgeParent()) {
3722 // Ignore updates if we're an out-of-process iframe. For oop iframes, our
3723 // |mFrameElement| is that of the top-level document, and so
3724 // AsyncTabSwitcher will treat MozLayerTreeReady / MozLayerTreeCleared
3725 // events as if they came from the top-level tab, which is wrong.
3726 return;
3729 if (mIsDestroyed) {
3730 return;
3733 RefPtr<Element> frameElement = mFrameElement;
3734 if (NS_WARN_IF(!frameElement)) {
3735 return;
3738 RefPtr<Event> event = NS_NewDOMEvent(frameElement, nullptr, nullptr);
3739 if (aActive) {
3740 event->InitEvent(u"MozLayerTreeReady"_ns, true, false);
3741 } else {
3742 event->InitEvent(u"MozLayerTreeCleared"_ns, true, false);
3744 event->SetTrusted(true);
3745 event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
3746 frameElement->DispatchEvent(*event);
3749 mozilla::ipc::IPCResult BrowserParent::RecvRemoteIsReadyToHandleInputEvents() {
3750 // When enabling input event prioritization, input events may preempt other
3751 // normal priority IPC messages. To prevent the input events preempt
3752 // PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to
3753 // notify the parent that BrowserChild is created and ready to handle input
3754 // events.
3755 SetReadyToHandleInputEvents();
3756 return IPC_OK();
3759 PPaymentRequestParent* BrowserParent::AllocPPaymentRequestParent() {
3760 RefPtr<PaymentRequestParent> actor = new PaymentRequestParent();
3761 return actor.forget().take();
3764 bool BrowserParent::DeallocPPaymentRequestParent(
3765 PPaymentRequestParent* aActor) {
3766 RefPtr<PaymentRequestParent> actor =
3767 dont_AddRef(static_cast<PaymentRequestParent*>(aActor));
3768 return true;
3771 nsresult BrowserParent::HandleEvent(Event* aEvent) {
3772 if (mIsDestroyed) {
3773 return NS_OK;
3776 nsAutoString eventType;
3777 aEvent->GetType(eventType);
3778 if (eventType.EqualsLiteral("MozUpdateWindowPos") ||
3779 eventType.EqualsLiteral("fullscreenchange")) {
3780 // Events that signify the window moving are used to update the position
3781 // and notify the BrowserChild.
3782 return UpdatePosition();
3784 return NS_OK;
3787 mozilla::ipc::IPCResult BrowserParent::RecvInvokeDragSession(
3788 nsTArray<IPCTransferableData>&& aTransferables, const uint32_t& aAction,
3789 Maybe<BigBuffer>&& aVisualDnDData, const uint32_t& aStride,
3790 const gfx::SurfaceFormat& aFormat, const LayoutDeviceIntRect& aDragRect,
3791 nsIPrincipal* aPrincipal, nsIContentSecurityPolicy* aCsp,
3792 const CookieJarSettingsArgs& aCookieJarSettingsArgs,
3793 const MaybeDiscarded<WindowContext>& aSourceWindowContext,
3794 const MaybeDiscarded<WindowContext>& aSourceTopWindowContext) {
3795 PresShell* presShell = mFrameElement->OwnerDoc()->GetPresShell();
3796 if (!presShell) {
3797 Unused << Manager()->SendEndDragSession(
3798 true, true, LayoutDeviceIntPoint(), 0,
3799 nsIDragService::DRAGDROP_ACTION_NONE);
3800 // Continue sending input events with input priority when stopping the dnd
3801 // session.
3802 Manager()->SetInputPriorityEventEnabled(true);
3803 return IPC_OK();
3806 nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
3807 net::CookieJarSettings::Deserialize(aCookieJarSettingsArgs,
3808 getter_AddRefs(cookieJarSettings));
3810 RefPtr<RemoteDragStartData> dragStartData = new RemoteDragStartData(
3811 this, std::move(aTransferables), aDragRect, aPrincipal, aCsp,
3812 cookieJarSettings, aSourceWindowContext.GetMaybeDiscarded(),
3813 aSourceTopWindowContext.GetMaybeDiscarded());
3815 if (aVisualDnDData) {
3816 const auto checkedSize = CheckedInt<size_t>(aDragRect.height) * aStride;
3817 if (checkedSize.isValid() &&
3818 aVisualDnDData->Size() >= checkedSize.value()) {
3819 dragStartData->SetVisualization(gfx::CreateDataSourceSurfaceFromData(
3820 gfx::IntSize(aDragRect.width, aDragRect.height), aFormat,
3821 aVisualDnDData->Data(), aStride));
3825 nsCOMPtr<nsIDragService> dragService =
3826 do_GetService("@mozilla.org/widget/dragservice;1");
3827 if (dragService) {
3828 dragService->MaybeAddChildProcess(Manager());
3831 presShell->GetPresContext()
3832 ->EventStateManager()
3833 ->BeginTrackingRemoteDragGesture(mFrameElement, dragStartData);
3835 return IPC_OK();
3838 bool BrowserParent::AsyncPanZoomEnabled() const {
3839 nsCOMPtr<nsIWidget> widget = GetWidget();
3840 return widget && widget->AsyncPanZoomEnabled();
3843 void BrowserParent::StartPersistence(
3844 CanonicalBrowsingContext* aContext,
3845 nsIWebBrowserPersistDocumentReceiver* aRecv, ErrorResult& aRv) {
3846 auto* actor = new WebBrowserPersistDocumentParent();
3847 actor->SetOnReady(aRecv);
3848 bool ok = Manager()->SendPWebBrowserPersistDocumentConstructor(actor, this,
3849 aContext);
3850 if (!ok) {
3851 aRv.Throw(NS_ERROR_FAILURE);
3853 // (The actor will be destroyed on constructor failure.)
3856 mozilla::ipc::IPCResult BrowserParent::RecvLookUpDictionary(
3857 const nsString& aText, nsTArray<FontRange>&& aFontRangeArray,
3858 const bool& aIsVertical, const LayoutDeviceIntPoint& aPoint) {
3859 nsCOMPtr<nsIWidget> widget = GetWidget();
3860 if (!widget) {
3861 return IPC_OK();
3864 widget->LookUpDictionary(aText, aFontRangeArray, aIsVertical,
3865 TransformChildToParent(aPoint));
3866 return IPC_OK();
3869 mozilla::ipc::IPCResult BrowserParent::RecvShowCanvasPermissionPrompt(
3870 const nsCString& aOrigin, const bool& aHideDoorHanger) {
3871 nsCOMPtr<nsIBrowser> browser =
3872 mFrameElement ? mFrameElement->AsBrowser() : nullptr;
3873 if (!browser) {
3874 // If the tab is being closed, the browser may not be available.
3875 // In this case we can ignore the request.
3876 return IPC_OK();
3878 nsCOMPtr<nsIObserverService> os = services::GetObserverService();
3879 if (!os) {
3880 return IPC_FAIL_NO_REASON(this);
3882 nsresult rv = os->NotifyObservers(
3883 browser,
3884 aHideDoorHanger ? "canvas-permissions-prompt-hide-doorhanger"
3885 : "canvas-permissions-prompt",
3886 NS_ConvertUTF8toUTF16(aOrigin).get());
3887 if (NS_FAILED(rv)) {
3888 return IPC_FAIL_NO_REASON(this);
3890 return IPC_OK();
3893 mozilla::ipc::IPCResult BrowserParent::RecvVisitURI(
3894 nsIURI* aURI, nsIURI* aLastVisitedURI, const uint32_t& aFlags,
3895 const uint64_t& aBrowserId) {
3896 if (!aURI) {
3897 return IPC_FAIL_NO_REASON(this);
3899 RefPtr<nsIWidget> widget = GetWidget();
3900 if (NS_WARN_IF(!widget)) {
3901 return IPC_OK();
3903 nsCOMPtr<IHistory> history = components::History::Service();
3904 if (history) {
3905 Unused << history->VisitURI(widget, aURI, aLastVisitedURI, aFlags,
3906 aBrowserId);
3908 return IPC_OK();
3911 mozilla::ipc::IPCResult BrowserParent::RecvQueryVisitedState(
3912 nsTArray<RefPtr<nsIURI>>&& aURIs) {
3913 #ifdef MOZ_ANDROID_HISTORY
3914 nsCOMPtr<IHistory> history = components::History::Service();
3915 if (NS_WARN_IF(!history)) {
3916 return IPC_OK();
3918 RefPtr<nsIWidget> widget = GetWidget();
3919 if (NS_WARN_IF(!widget)) {
3920 return IPC_OK();
3923 // FIXME(emilio): Is this check really needed?
3924 for (nsIURI* uri : aURIs) {
3925 if (!uri) {
3926 return IPC_FAIL(this, "Received null URI");
3930 auto* gvHistory = static_cast<GeckoViewHistory*>(history.get());
3931 gvHistory->QueryVisitedState(widget, mManager, std::move(aURIs));
3932 return IPC_OK();
3933 #else
3934 return IPC_FAIL(this, "QueryVisitedState is Android-only");
3935 #endif
3938 void BrowserParent::LiveResizeStarted() { SuppressDisplayport(true); }
3940 void BrowserParent::LiveResizeStopped() { SuppressDisplayport(false); }
3942 void BrowserParent::SetBrowserBridgeParent(BrowserBridgeParent* aBrowser) {
3943 // We should either be clearing out our reference to a browser bridge, or not
3944 // have either a browser bridge, browser host, or owner content yet.
3945 MOZ_ASSERT(!aBrowser ||
3946 (!mBrowserBridgeParent && !mBrowserHost && !mFrameElement));
3947 mBrowserBridgeParent = aBrowser;
3950 void BrowserParent::SetBrowserHost(BrowserHost* aBrowser) {
3951 // We should either be clearing out our reference to a browser host, or not
3952 // have either a browser bridge, browser host, or owner content yet.
3953 MOZ_ASSERT(!aBrowser ||
3954 (!mBrowserBridgeParent && !mBrowserHost && !mFrameElement));
3955 mBrowserHost = aBrowser;
3958 mozilla::ipc::IPCResult BrowserParent::RecvSetSystemFont(
3959 const nsCString& aFontName) {
3960 nsCOMPtr<nsIWidget> widget = GetWidget();
3961 if (widget) {
3962 widget->SetSystemFont(aFontName);
3964 return IPC_OK();
3967 mozilla::ipc::IPCResult BrowserParent::RecvGetSystemFont(nsCString* aFontName) {
3968 nsCOMPtr<nsIWidget> widget = GetWidget();
3969 if (widget) {
3970 widget->GetSystemFont(*aFontName);
3972 return IPC_OK();
3975 mozilla::ipc::IPCResult BrowserParent::RecvMaybeFireEmbedderLoadEvents(
3976 EmbedderElementEventType aFireEventAtEmbeddingElement) {
3977 BrowserBridgeParent* bridge = GetBrowserBridgeParent();
3978 if (!bridge) {
3979 NS_WARNING("Received `load` event on unbridged BrowserParent!");
3980 return IPC_OK();
3983 Unused << bridge->SendMaybeFireEmbedderLoadEvents(
3984 aFireEventAtEmbeddingElement);
3985 return IPC_OK();
3988 mozilla::ipc::IPCResult BrowserParent::RecvScrollRectIntoView(
3989 const nsRect& aRect, const ScrollAxis& aVertical,
3990 const ScrollAxis& aHorizontal, const ScrollFlags& aScrollFlags,
3991 const int32_t& aAppUnitsPerDevPixel) {
3992 BrowserBridgeParent* bridge = GetBrowserBridgeParent();
3993 if (!bridge || !bridge->CanSend()) {
3994 return IPC_OK();
3997 Unused << bridge->SendScrollRectIntoView(aRect, aVertical, aHorizontal,
3998 aScrollFlags, aAppUnitsPerDevPixel);
3999 return IPC_OK();
4002 mozilla::ipc::IPCResult BrowserParent::RecvIsWindowSupportingProtectedMedia(
4003 const uint64_t& aOuterWindowID,
4004 IsWindowSupportingProtectedMediaResolver&& aResolve) {
4005 #ifdef XP_WIN
4006 bool isFxrWindow =
4007 FxRWindowManager::GetInstance()->IsFxRWindow(aOuterWindowID);
4008 aResolve(!isFxrWindow);
4009 #else
4010 # ifdef FUZZING_SNAPSHOT
4011 return IPC_FAIL(this, "Should only be called on Windows");
4012 # endif
4013 MOZ_CRASH("Should only be called on Windows");
4014 #endif
4016 return IPC_OK();
4019 mozilla::ipc::IPCResult BrowserParent::RecvIsWindowSupportingWebVR(
4020 const uint64_t& aOuterWindowID,
4021 IsWindowSupportingWebVRResolver&& aResolve) {
4022 #ifdef XP_WIN
4023 bool isFxrWindow =
4024 FxRWindowManager::GetInstance()->IsFxRWindow(aOuterWindowID);
4025 aResolve(!isFxrWindow);
4026 #else
4027 aResolve(true);
4028 #endif
4030 return IPC_OK();
4033 static BrowserParent* GetTopLevelBrowserParent(BrowserParent* aBrowserParent) {
4034 MOZ_ASSERT(aBrowserParent);
4035 BrowserParent* parent = aBrowserParent;
4036 while (BrowserBridgeParent* bridge = parent->GetBrowserBridgeParent()) {
4037 parent = bridge->Manager();
4039 return parent;
4042 mozilla::ipc::IPCResult BrowserParent::RecvRequestPointerLock(
4043 RequestPointerLockResolver&& aResolve) {
4044 nsCString error;
4045 if (sTopLevelWebFocus != GetTopLevelBrowserParent(this)) {
4046 error = "PointerLockDeniedNotFocused";
4047 } else if (!PointerLockManager::SetLockedRemoteTarget(this)) {
4048 error = "PointerLockDeniedInUse";
4049 } else {
4050 PointerEventHandler::ReleaseAllPointerCaptureRemoteTarget();
4052 aResolve(error);
4053 return IPC_OK();
4056 mozilla::ipc::IPCResult BrowserParent::RecvReleasePointerLock() {
4057 MOZ_ASSERT_IF(PointerLockManager::GetLockedRemoteTarget(),
4058 PointerLockManager::GetLockedRemoteTarget() == this);
4059 PointerLockManager::ReleaseLockedRemoteTarget(this);
4060 return IPC_OK();
4063 mozilla::ipc::IPCResult BrowserParent::RecvRequestPointerCapture(
4064 const uint32_t& aPointerId, RequestPointerCaptureResolver&& aResolve) {
4065 aResolve(
4066 PointerEventHandler::SetPointerCaptureRemoteTarget(aPointerId, this));
4067 return IPC_OK();
4070 mozilla::ipc::IPCResult BrowserParent::RecvReleasePointerCapture(
4071 const uint32_t& aPointerId) {
4072 PointerEventHandler::ReleasePointerCaptureRemoteTarget(aPointerId);
4073 return IPC_OK();
4076 mozilla::ipc::IPCResult BrowserParent::RecvShowDynamicToolbar() {
4077 #if defined(MOZ_WIDGET_ANDROID)
4078 nsCOMPtr<nsIWidget> widget = GetTopLevelWidget();
4079 if (!widget) {
4080 return IPC_OK();
4083 RefPtr<nsWindow> window = nsWindow::From(widget);
4084 if (!window) {
4085 return IPC_OK();
4088 window->ShowDynamicToolbar();
4089 #endif // defined(MOZ_WIDGET_ANDROID)
4090 return IPC_OK();
4093 } // namespace dom
4094 } // namespace mozilla