summaryrefslogtreecommitdiffstats
path: root/dom/ipc/BrowserParent.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /dom/ipc/BrowserParent.cpp
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/ipc/BrowserParent.cpp')
-rw-r--r--dom/ipc/BrowserParent.cpp4125
1 files changed, 4125 insertions, 0 deletions
diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp
new file mode 100644
index 0000000000..5ede68022d
--- /dev/null
+++ b/dom/ipc/BrowserParent.cpp
@@ -0,0 +1,4125 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "base/basictypes.h"
+
+#include "BrowserParent.h"
+
+#ifdef ACCESSIBILITY
+# include "mozilla/a11y/DocAccessibleParent.h"
+# include "mozilla/a11y/Platform.h"
+# include "mozilla/a11y/ProxyAccessibleBase.h"
+# include "nsAccessibilityService.h"
+#endif
+#include "mozilla/dom/BrowserHost.h"
+#include "mozilla/dom/BrowsingContextGroup.h"
+#include "mozilla/dom/CancelContentJSOptionsBinding.h"
+#include "mozilla/dom/ChromeMessageSender.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/ContentProcessManager.h"
+#include "mozilla/dom/DataTransfer.h"
+#include "mozilla/dom/DataTransferItemList.h"
+#include "mozilla/dom/Event.h"
+#include "mozilla/dom/indexedDB/ActorsParent.h"
+#include "mozilla/dom/PaymentRequestParent.h"
+#include "mozilla/dom/PointerEventHandler.h"
+#include "mozilla/dom/BrowserBridgeParent.h"
+#include "mozilla/dom/RemoteDragStartData.h"
+#include "mozilla/dom/RemoteWebProgress.h"
+#include "mozilla/dom/RemoteWebProgressRequest.h"
+#include "mozilla/dom/SessionHistoryEntry.h"
+#include "mozilla/dom/SessionStoreUtils.h"
+#include "mozilla/dom/SessionStoreUtilsBinding.h"
+#include "mozilla/dom/UserActivation.h"
+#include "mozilla/EventStateManager.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/DataSurfaceHelpers.h"
+#include "mozilla/gfx/GPUProcessManager.h"
+#include "mozilla/Hal.h"
+#include "mozilla/IMEStateManager.h"
+#include "mozilla/ipc/Endpoint.h"
+#include "mozilla/layers/AsyncDragMetrics.h"
+#include "mozilla/layers/InputAPZContext.h"
+#include "mozilla/layout/RemoteLayerTreeOwner.h"
+#include "mozilla/plugins/PPluginWidgetParent.h"
+#include "mozilla/LookAndFeel.h"
+#include "mozilla/MiscEvents.h"
+#include "mozilla/MouseEvents.h"
+#include "mozilla/net/NeckoChild.h"
+#include "mozilla/net/CookieJarSettings.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/PresShell.h"
+#include "mozilla/ProcessHangMonitor.h"
+#include "mozilla/StaticPrefs_dom.h"
+#include "mozilla/TextEvents.h"
+#include "mozilla/TouchEvents.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Unused.h"
+#include "nsCOMPtr.h"
+#include "nsContentUtils.h"
+#include "nsDebug.h"
+#include "nsFocusManager.h"
+#include "nsFrameLoader.h"
+#include "nsFrameLoaderOwner.h"
+#include "nsFrameManager.h"
+#include "nsIBaseWindow.h"
+#include "nsIBrowser.h"
+#include "nsIBrowserController.h"
+#include "nsIContent.h"
+#include "nsICookieJarSettings.h"
+#include "nsIDocShell.h"
+#include "nsIDocShellTreeOwner.h"
+#include "nsImportModule.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsILoadInfo.h"
+#include "nsIPromptFactory.h"
+#include "nsIURI.h"
+#include "nsIWebBrowserChrome.h"
+#include "nsIWebProtocolHandlerRegistrar.h"
+#include "nsIWindowWatcher.h"
+#include "nsIXPConnect.h"
+#include "nsIXULBrowserWindow.h"
+#include "nsIAppWindow.h"
+#include "nsLayoutUtils.h"
+#include "nsQueryActor.h"
+#include "nsSHistory.h"
+#include "nsViewManager.h"
+#include "nsVariant.h"
+#include "nsIWidget.h"
+#include "nsNetUtil.h"
+#ifndef XP_WIN
+# include "nsJARProtocolHandler.h"
+#endif
+#include "nsPIDOMWindow.h"
+#include "nsPrintfCString.h"
+#include "nsQueryObject.h"
+#include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
+#include "PermissionMessageUtils.h"
+#include "StructuredCloneData.h"
+#include "ColorPickerParent.h"
+#include "FilePickerParent.h"
+#include "BrowserChild.h"
+#include "nsNetCID.h"
+#include "nsIAuthInformation.h"
+#include "nsIAuthPromptCallback.h"
+#include "nsAuthInformationHolder.h"
+#include "nsICancelable.h"
+#include "gfxUtils.h"
+#include "nsILoginManagerAuthPrompter.h"
+#include "nsPIWindowRoot.h"
+#include "nsReadableUtils.h"
+#include "nsIAuthPrompt2.h"
+#include "gfxDrawable.h"
+#include "ImageOps.h"
+#include "UnitTransforms.h"
+#include <algorithm>
+#include "mozilla/NullPrincipal.h"
+#include "mozilla/WebBrowserPersistDocumentParent.h"
+#include "ProcessPriorityManager.h"
+#include "nsString.h"
+#include "IHistory.h"
+#include "mozilla/dom/WindowGlobalParent.h"
+#include "mozilla/dom/CanonicalBrowsingContext.h"
+#include "GeckoProfiler.h"
+#include "MMPrinter.h"
+#include "SessionStoreFunctions.h"
+#include "mozilla/dom/CrashReport.h"
+#include "nsISecureBrowserUI.h"
+#include "nsIXULRuntime.h"
+#include "VsyncSource.h"
+
+#ifdef XP_WIN
+# include "mozilla/plugins/PluginWidgetParent.h"
+# include "FxRWindowManager.h"
+#endif
+
+#if defined(XP_WIN) && defined(ACCESSIBILITY)
+# include "mozilla/a11y/AccessibleWrap.h"
+# include "mozilla/a11y/Compatibility.h"
+# include "mozilla/a11y/nsWinUtils.h"
+#endif
+
+#ifdef MOZ_ANDROID_HISTORY
+# include "GeckoViewHistory.h"
+#endif
+
+using namespace mozilla::dom;
+using namespace mozilla::ipc;
+using namespace mozilla::layers;
+using namespace mozilla::layout;
+using namespace mozilla::services;
+using namespace mozilla::widget;
+using namespace mozilla::gfx;
+
+using mozilla::LazyLogModule;
+using mozilla::StaticAutoPtr;
+using mozilla::Unused;
+
+LazyLogModule gBrowserFocusLog("BrowserFocus");
+
+#define LOGBROWSERFOCUS(args) \
+ MOZ_LOG(gBrowserFocusLog, mozilla::LogLevel::Debug, args)
+
+/* static */
+BrowserParent* BrowserParent::sFocus = nullptr;
+/* static */
+BrowserParent* BrowserParent::sTopLevelWebFocus = nullptr;
+/* static */
+BrowserParent* BrowserParent::sLastMouseRemoteTarget = nullptr;
+/* static */
+BrowserParent* BrowserParent::sPointerLockedRemoteTarget = nullptr;
+
+// The flags passed by the webProgress notifications are 16 bits shifted
+// from the ones registered by webProgressListeners.
+#define NOTIFY_FLAG_SHIFT 16
+
+namespace mozilla::dom {
+
+BrowserParent::LayerToBrowserParentTable*
+ BrowserParent::sLayerToBrowserParentTable = nullptr;
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowserParent)
+ NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
+ NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener)
+NS_INTERFACE_MAP_END
+NS_IMPL_CYCLE_COLLECTION_WEAK(BrowserParent, mFrameLoader, mBrowsingContext)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(BrowserParent)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(BrowserParent)
+
+BrowserParent::BrowserParent(ContentParent* aManager, const TabId& aTabId,
+ const TabContext& aContext,
+ CanonicalBrowsingContext* aBrowsingContext,
+ uint32_t aChromeFlags)
+ : TabContext(aContext),
+ mTabId(aTabId),
+ mManager(aManager),
+ mBrowsingContext(aBrowsingContext),
+ mFrameElement(nullptr),
+ mBrowserDOMWindow(nullptr),
+ mFrameLoader(nullptr),
+ mChromeFlags(aChromeFlags),
+ mBrowserBridgeParent(nullptr),
+ mBrowserHost(nullptr),
+ mContentCache(*this),
+ mRemoteLayerTreeOwner{},
+ mLayerTreeEpoch{1},
+ mChildToParentConversionMatrix{},
+ mRect(0, 0, 0, 0),
+ mDimensions(0, 0),
+ mOrientation(0),
+ mDPI(0),
+ mRounding(0),
+ mDefaultScale(0),
+ mUpdatedDimensions(false),
+ mSizeMode(nsSizeMode_Normal),
+ mClientOffset{},
+ mChromeOffset{},
+ mCreatingWindow(false),
+ mDelayedFrameScripts{},
+ mCursor(eCursorInvalid),
+ mCustomCursor{},
+ mCustomCursorHotspotX(0),
+ mCustomCursorHotspotY(0),
+ mVerifyDropLinks{},
+ mVsyncParent(nullptr),
+ mMarkedDestroying(false),
+ mIsDestroyed(false),
+ mRemoteTargetSetsCursor(false),
+ mPreserveLayers(false),
+ mRenderLayers(true),
+ mActiveInPriorityManager(false),
+ mHasLayers(false),
+ mHasPresented(false),
+ mIsReadyToHandleInputEvents(false),
+ mIsMouseEnterIntoWidgetEventSuppressed(false),
+ mSuspendedProgressEvents(false) {
+ MOZ_ASSERT(aManager);
+ // When the input event queue is disabled, we don't need to handle the case
+ // that some input events are dispatched before PBrowserConstructor.
+ mIsReadyToHandleInputEvents = !ContentParent::IsInputEventQueueSupported();
+}
+
+BrowserParent::~BrowserParent() = default;
+
+/* static */
+BrowserParent* BrowserParent::GetFocused() { return sFocus; }
+
+/* static */
+BrowserParent* BrowserParent::GetLastMouseRemoteTarget() {
+ return sLastMouseRemoteTarget;
+}
+
+/* static */
+BrowserParent* BrowserParent::GetPointerLockedRemoteTarget() {
+ return sPointerLockedRemoteTarget;
+}
+
+/*static*/
+BrowserParent* BrowserParent::GetFrom(nsFrameLoader* aFrameLoader) {
+ if (!aFrameLoader) {
+ return nullptr;
+ }
+ return aFrameLoader->GetBrowserParent();
+}
+
+/*static*/
+BrowserParent* BrowserParent::GetFrom(PBrowserParent* aBrowserParent) {
+ return static_cast<BrowserParent*>(aBrowserParent);
+}
+
+/*static*/
+BrowserParent* BrowserParent::GetFrom(nsIContent* aContent) {
+ RefPtr<nsFrameLoaderOwner> loaderOwner = do_QueryObject(aContent);
+ if (!loaderOwner) {
+ return nullptr;
+ }
+ RefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
+ return GetFrom(frameLoader);
+}
+
+/* static */
+BrowserParent* BrowserParent::GetBrowserParentFromLayersId(
+ layers::LayersId aLayersId) {
+ if (!sLayerToBrowserParentTable) {
+ return nullptr;
+ }
+ return sLayerToBrowserParentTable->Get(uint64_t(aLayersId));
+}
+
+/*static*/
+TabId BrowserParent::GetTabIdFrom(nsIDocShell* docShell) {
+ nsCOMPtr<nsIBrowserChild> browserChild(BrowserChild::GetFrom(docShell));
+ if (browserChild) {
+ return static_cast<BrowserChild*>(browserChild.get())->GetTabId();
+ }
+ return TabId(0);
+}
+
+void BrowserParent::AddBrowserParentToTable(layers::LayersId aLayersId,
+ BrowserParent* aBrowserParent) {
+ if (!sLayerToBrowserParentTable) {
+ sLayerToBrowserParentTable = new LayerToBrowserParentTable();
+ }
+ sLayerToBrowserParentTable->Put(uint64_t(aLayersId), aBrowserParent);
+}
+
+void BrowserParent::RemoveBrowserParentFromTable(layers::LayersId aLayersId) {
+ if (!sLayerToBrowserParentTable) {
+ return;
+ }
+ sLayerToBrowserParentTable->Remove(uint64_t(aLayersId));
+ if (sLayerToBrowserParentTable->Count() == 0) {
+ delete sLayerToBrowserParentTable;
+ sLayerToBrowserParentTable = nullptr;
+ }
+}
+
+already_AddRefed<nsILoadContext> BrowserParent::GetLoadContext() {
+ return do_AddRef(mBrowsingContext);
+}
+
+/**
+ * Will return nullptr if there is no outer window available for the
+ * document hosting the owner element of this BrowserParent. Also will return
+ * nullptr if that outer window is in the process of closing.
+ */
+already_AddRefed<nsPIDOMWindowOuter> BrowserParent::GetParentWindowOuter() {
+ nsCOMPtr<nsIContent> frame = GetOwnerElement();
+ if (!frame) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsPIDOMWindowOuter> parent = frame->OwnerDoc()->GetWindow();
+ if (!parent || parent->Closed()) {
+ return nullptr;
+ }
+
+ return parent.forget();
+}
+
+already_AddRefed<nsIWidget> BrowserParent::GetTopLevelWidget() {
+ if (RefPtr<Element> element = mFrameElement) {
+ if (PresShell* presShell = element->OwnerDoc()->GetPresShell()) {
+ nsViewManager* vm = presShell->GetViewManager();
+ nsCOMPtr<nsIWidget> widget;
+ vm->GetRootWidget(getter_AddRefs(widget));
+ return widget.forget();
+ }
+ }
+ return nullptr;
+}
+
+already_AddRefed<nsIWidget> BrowserParent::GetTextInputHandlingWidget() const {
+ if (!mFrameElement) {
+ return nullptr;
+ }
+ PresShell* presShell = mFrameElement->OwnerDoc()->GetPresShell();
+ if (!presShell) {
+ return nullptr;
+ }
+ nsPresContext* presContext = presShell->GetPresContext();
+ if (!presContext) {
+ return nullptr;
+ }
+ nsCOMPtr<nsIWidget> widget = presContext->GetTextInputHandlingWidget();
+ return widget.forget();
+}
+
+already_AddRefed<nsIWidget> BrowserParent::GetWidget() const {
+ if (!mFrameElement) {
+ return nullptr;
+ }
+ nsCOMPtr<nsIWidget> widget = nsContentUtils::WidgetForContent(mFrameElement);
+ if (!widget) {
+ widget = nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc());
+ }
+ return widget.forget();
+}
+
+already_AddRefed<nsIWidget> BrowserParent::GetDocWidget() const {
+ if (!mFrameElement) {
+ return nullptr;
+ }
+ return do_AddRef(
+ nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc()));
+}
+
+nsIXULBrowserWindow* BrowserParent::GetXULBrowserWindow() {
+ if (!mFrameElement) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIDocShell> docShell = mFrameElement->OwnerDoc()->GetDocShell();
+ if (!docShell) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
+ docShell->GetTreeOwner(getter_AddRefs(treeOwner));
+ if (!treeOwner) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIAppWindow> window = do_GetInterface(treeOwner);
+ if (!window) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow;
+ window->GetXULBrowserWindow(getter_AddRefs(xulBrowserWindow));
+ return xulBrowserWindow;
+}
+
+uint32_t BrowserParent::GetMaxTouchPoints(Element* aElement) {
+ if (!aElement) {
+ return 0;
+ }
+
+ if (StaticPrefs::dom_maxtouchpoints_testing_value() >= 0) {
+ return StaticPrefs::dom_maxtouchpoints_testing_value();
+ }
+
+ nsIWidget* widget = nsContentUtils::WidgetForDocument(aElement->OwnerDoc());
+ return widget ? widget->GetMaxTouchPoints() : 0;
+}
+
+a11y::DocAccessibleParent* BrowserParent::GetTopLevelDocAccessible() const {
+#ifdef ACCESSIBILITY
+ // XXX Consider managing non top level PDocAccessibles with their parent
+ // document accessible.
+ const ManagedContainer<PDocAccessibleParent>& docs =
+ ManagedPDocAccessibleParent();
+ for (auto iter = docs.ConstIter(); !iter.Done(); iter.Next()) {
+ auto doc = static_cast<a11y::DocAccessibleParent*>(iter.Get()->GetKey());
+ // We want the document for this BrowserParent even if it's for an
+ // embedded out-of-process iframe. Therefore, we use
+ // IsTopLevelInContentProcess. In contrast, using IsToplevel would only
+ // include documents that aren't embedded; e.g. tab documents.
+ if (doc->IsTopLevelInContentProcess()) {
+ return doc;
+ }
+ }
+
+ MOZ_ASSERT(docs.Count() == 0,
+ "If there isn't a top level accessible doc "
+ "there shouldn't be an accessible doc at all!");
+#endif
+ return nullptr;
+}
+
+LayersId BrowserParent::GetLayersId() const {
+ if (!mRemoteLayerTreeOwner.IsInitialized()) {
+ return LayersId{};
+ }
+ return mRemoteLayerTreeOwner.GetLayersId();
+}
+
+BrowserBridgeParent* BrowserParent::GetBrowserBridgeParent() const {
+ return mBrowserBridgeParent;
+}
+
+BrowserHost* BrowserParent::GetBrowserHost() const { return mBrowserHost; }
+
+ParentShowInfo BrowserParent::GetShowInfo() {
+ TryCacheDPIAndScale();
+ if (mFrameElement) {
+ nsAutoString name;
+ mFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
+ bool isTransparent =
+ nsContentUtils::IsChromeDoc(mFrameElement->OwnerDoc()) &&
+ mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::transparent);
+ return ParentShowInfo(name, false, isTransparent, mDPI, mRounding,
+ mDefaultScale.scale);
+ }
+
+ return ParentShowInfo(u""_ns, false, false, mDPI, mRounding,
+ mDefaultScale.scale);
+}
+
+already_AddRefed<nsIPrincipal> BrowserParent::GetContentPrincipal() const {
+ nsCOMPtr<nsIBrowser> browser =
+ mFrameElement ? mFrameElement->AsBrowser() : nullptr;
+ NS_ENSURE_TRUE(browser, nullptr);
+
+ RefPtr<nsIPrincipal> principal;
+
+ nsresult rv;
+ rv = browser->GetContentPrincipal(getter_AddRefs(principal));
+ NS_ENSURE_SUCCESS(rv, nullptr);
+
+ return principal.forget();
+}
+
+void BrowserParent::SetOwnerElement(Element* aElement) {
+ // If we held previous content then unregister for its events.
+ RemoveWindowListeners();
+
+ // If we change top-level documents then we need to change our
+ // registration with them.
+ RefPtr<nsPIWindowRoot> curTopLevelWin, newTopLevelWin;
+ if (mFrameElement) {
+ curTopLevelWin = nsContentUtils::GetWindowRoot(mFrameElement->OwnerDoc());
+ }
+ if (aElement) {
+ newTopLevelWin = nsContentUtils::GetWindowRoot(aElement->OwnerDoc());
+ }
+ bool isSameTopLevelWin = curTopLevelWin == newTopLevelWin;
+ if (mBrowserHost && curTopLevelWin && !isSameTopLevelWin) {
+ curTopLevelWin->RemoveBrowser(mBrowserHost);
+ }
+
+ // Update to the new content, and register to listen for events from it.
+ mFrameElement = aElement;
+
+ if (mBrowserHost && newTopLevelWin && !isSameTopLevelWin) {
+ newTopLevelWin->AddBrowser(mBrowserHost);
+ }
+
+#if defined(XP_WIN) && defined(ACCESSIBILITY)
+ if (!mIsDestroyed) {
+ uintptr_t newWindowHandle = 0;
+ if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
+ newWindowHandle =
+ reinterpret_cast<uintptr_t>(widget->GetNativeData(NS_NATIVE_WINDOW));
+ }
+ Unused << SendUpdateNativeWindowHandle(newWindowHandle);
+ a11y::DocAccessibleParent* doc = GetTopLevelDocAccessible();
+ if (doc) {
+ HWND hWnd = reinterpret_cast<HWND>(doc->GetEmulatedWindowHandle());
+ if (hWnd) {
+ HWND parentHwnd = reinterpret_cast<HWND>(newWindowHandle);
+ if (parentHwnd != ::GetParent(hWnd)) {
+ ::SetParent(hWnd, parentHwnd);
+ }
+ }
+ }
+ }
+#endif
+
+ AddWindowListeners();
+ TryCacheDPIAndScale();
+
+ // Try to send down WidgetNativeData, now that this BrowserParent is
+ // associated with a widget.
+ nsCOMPtr<nsIWidget> widget = GetTopLevelWidget();
+ if (widget) {
+ WindowsHandle widgetNativeData = reinterpret_cast<WindowsHandle>(
+ widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW));
+ if (widgetNativeData) {
+ Unused << SendSetWidgetNativeData(widgetNativeData);
+ }
+ }
+
+ if (mRemoteLayerTreeOwner.IsInitialized()) {
+ mRemoteLayerTreeOwner.OwnerContentChanged();
+ }
+
+ // Set our BrowsingContext's embedder if we're not embedded within a
+ // BrowserBridgeParent.
+ if (!GetBrowserBridgeParent() && mBrowsingContext && mFrameElement) {
+ mBrowsingContext->SetEmbedderElement(mFrameElement);
+ }
+
+ UpdateVsyncParentVsyncSource();
+
+ VisitChildren([aElement](BrowserBridgeParent* aBrowser) {
+ if (auto* browserParent = aBrowser->GetBrowserParent()) {
+ browserParent->SetOwnerElement(aElement);
+ }
+ });
+}
+
+void BrowserParent::CacheFrameLoader(nsFrameLoader* aFrameLoader) {
+ mFrameLoader = aFrameLoader;
+}
+
+void BrowserParent::AddWindowListeners() {
+ if (mFrameElement) {
+ if (nsCOMPtr<nsPIDOMWindowOuter> window =
+ mFrameElement->OwnerDoc()->GetWindow()) {
+ nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
+ if (eventTarget) {
+ eventTarget->AddEventListener(u"MozUpdateWindowPos"_ns, this, false,
+ false);
+ eventTarget->AddEventListener(u"fullscreenchange"_ns, this, false,
+ false);
+ }
+ }
+ }
+}
+
+void BrowserParent::RemoveWindowListeners() {
+ if (mFrameElement && mFrameElement->OwnerDoc()->GetWindow()) {
+ nsCOMPtr<nsPIDOMWindowOuter> window =
+ mFrameElement->OwnerDoc()->GetWindow();
+ nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
+ if (eventTarget) {
+ eventTarget->RemoveEventListener(u"MozUpdateWindowPos"_ns, this, false);
+ eventTarget->RemoveEventListener(u"fullscreenchange"_ns, this, false);
+ }
+ }
+}
+
+void BrowserParent::DestroyInternal() {
+ UnsetTopLevelWebFocus(this);
+ UnsetLastMouseRemoteTarget(this);
+ UnsetPointerLockedRemoteTarget(this);
+ PointerEventHandler::ReleasePointerCaptureRemoteTarget(this);
+ PresShell::ReleaseCapturingRemoteTarget(this);
+
+ RemoveWindowListeners();
+
+#ifdef ACCESSIBILITY
+ if (a11y::DocAccessibleParent* tabDoc = GetTopLevelDocAccessible()) {
+ tabDoc->Destroy();
+ }
+#endif
+
+ // If this fails, it's most likely due to a content-process crash,
+ // and auto-cleanup will kick in. Otherwise, the child side will
+ // destroy itself and send back __delete__().
+ Unused << SendDestroy();
+
+#ifdef XP_WIN
+ // Let all PluginWidgets know we are tearing down. Prevents
+ // these objects from sending async events after the child side
+ // is shut down.
+ const ManagedContainer<PPluginWidgetParent>& kids =
+ ManagedPPluginWidgetParent();
+ for (auto iter = kids.ConstIter(); !iter.Done(); iter.Next()) {
+ static_cast<mozilla::plugins::PluginWidgetParent*>(iter.Get()->GetKey())
+ ->ParentDestroy();
+ }
+#endif
+}
+
+void BrowserParent::Destroy() {
+ // Aggressively release the window to avoid leaking the world in shutdown
+ // corner cases.
+ mBrowserDOMWindow = nullptr;
+
+ if (mIsDestroyed) {
+ return;
+ }
+
+ DestroyInternal();
+
+ mIsDestroyed = true;
+
+ Manager()->NotifyTabDestroying();
+
+ // This `AddKeepAlive` will be cleared if `mMarkedDestroying` is set in
+ // `ActorDestroy`. Out of caution, we don't add the `KeepAlive` if our IPC
+ // actor has somehow already been destroyed, as that would mean `ActorDestroy`
+ // won't be called.
+ if (CanRecv()) {
+ mBrowsingContext->Group()->AddKeepAlive();
+ }
+
+ mMarkedDestroying = true;
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvEnsureLayersConnected(
+ CompositorOptions* aCompositorOptions) {
+ if (mRemoteLayerTreeOwner.IsInitialized()) {
+ mRemoteLayerTreeOwner.EnsureLayersConnected(aCompositorOptions);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::Recv__delete__() {
+ Manager()->NotifyTabDestroyed(mTabId, mMarkedDestroying);
+ return IPC_OK();
+}
+
+void BrowserParent::ActorDestroy(ActorDestroyReason why) {
+ ContentProcessManager::GetSingleton()->UnregisterRemoteFrame(mTabId);
+
+ if (mRemoteLayerTreeOwner.IsInitialized()) {
+ // It's important to unmap layers after the remote browser has been
+ // destroyed, otherwise it may still send messages to the compositor which
+ // will reject them, causing assertions.
+ RemoveBrowserParentFromTable(mRemoteLayerTreeOwner.GetLayersId());
+ mRemoteLayerTreeOwner.Destroy();
+ }
+
+ // Even though BrowserParent::Destroy calls this, we need to do it here too in
+ // case of a crash.
+ BrowserParent::UnsetTopLevelWebFocus(this);
+ BrowserParent::UnsetLastMouseRemoteTarget(this);
+ BrowserParent::UnsetPointerLockedRemoteTarget(this);
+ PointerEventHandler::ReleasePointerCaptureRemoteTarget(this);
+ PresShell::ReleaseCapturingRemoteTarget(this);
+
+ if (why == AbnormalShutdown) {
+ // dom_reporting_header must also be enabled for the report to be sent.
+ if (StaticPrefs::dom_reporting_crash_enabled()) {
+ nsCOMPtr<nsIPrincipal> principal = GetContentPrincipal();
+
+ if (principal) {
+ nsAutoCString crash_reason;
+ CrashReporter::GetAnnotation(OtherPid(),
+ CrashReporter::Annotation::MozCrashReason,
+ crash_reason);
+ // FIXME(arenevier): Find a less fragile way to identify that a crash
+ // was caused by OOM
+ bool is_oom = false;
+ if (crash_reason == "OOM" || crash_reason == "OOM!" ||
+ StringBeginsWith(crash_reason, "[unhandlable oom]"_ns) ||
+ StringBeginsWith(crash_reason, "Unhandlable OOM"_ns)) {
+ is_oom = true;
+ }
+
+ CrashReport::Deliver(principal, is_oom);
+ }
+ }
+ }
+
+ // If we were shutting down normally, we held a reference to our
+ // BrowsingContextGroup in `BrowserParent::Destroy`. Clear that reference
+ // here.
+ if (mMarkedDestroying) {
+ mBrowsingContext->Group()->RemoveKeepAlive();
+ }
+
+ // Tell our embedder that the tab is now going away unless we're an
+ // out-of-process iframe.
+ RefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
+ if (frameLoader) {
+ ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr);
+
+ if (mBrowsingContext->IsTop()) {
+ // If this is a top-level BrowsingContext, tell the frameloader it's time
+ // to go away. Otherwise, this is a subframe crash, and we can keep the
+ // frameloader around.
+ frameLoader->DestroyComplete();
+ }
+
+ // If this was a crash, tell our nsFrameLoader to fire crash events.
+ if (why == AbnormalShutdown) {
+ frameLoader->MaybeNotifyCrashed(mBrowsingContext, Manager()->ChildID(),
+ GetIPCChannel());
+
+ auto* bridge = GetBrowserBridgeParent();
+ if (bridge && bridge->CanSend() && !mBrowsingContext->IsDiscarded()) {
+ MOZ_ASSERT(!mBrowsingContext->IsTop());
+
+ // Set the owner process of the root context belonging to a crashed
+ // process to the embedding process, since we'll be showing the crashed
+ // page in that process.
+ mBrowsingContext->SetOwnerProcessId(
+ bridge->Manager()->Manager()->ChildID());
+ MOZ_ALWAYS_SUCCEEDS(mBrowsingContext->SetCurrentInnerWindowId(0));
+
+ // Tell the browser bridge to show the subframe crashed page.
+ Unused << bridge->SendSubFrameCrashed();
+ }
+ }
+ }
+
+ mFrameLoader = nullptr;
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvMoveFocus(
+ const bool& aForward, const bool& aForDocumentNavigation) {
+ LOGBROWSERFOCUS(("RecvMoveFocus %p, aForward: %d, aForDocumentNavigation: %d",
+ this, aForward, aForDocumentNavigation));
+ BrowserBridgeParent* bridgeParent = GetBrowserBridgeParent();
+ if (bridgeParent) {
+ mozilla::Unused << bridgeParent->SendMoveFocus(aForward,
+ aForDocumentNavigation);
+ return IPC_OK();
+ }
+
+ RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager();
+ if (fm) {
+ RefPtr<Element> dummy;
+
+ uint32_t type =
+ aForward
+ ? (aForDocumentNavigation
+ ? static_cast<uint32_t>(
+ nsIFocusManager::MOVEFOCUS_FORWARDDOC)
+ : static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARD))
+ : (aForDocumentNavigation
+ ? static_cast<uint32_t>(
+ nsIFocusManager::MOVEFOCUS_BACKWARDDOC)
+ : static_cast<uint32_t>(
+ nsIFocusManager::MOVEFOCUS_BACKWARD));
+ fm->MoveFocus(nullptr, mFrameElement, type, nsIFocusManager::FLAG_BYKEY,
+ getter_AddRefs(dummy));
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSizeShellTo(
+ const uint32_t& aFlags, const int32_t& aWidth, const int32_t& aHeight,
+ const int32_t& aShellItemWidth, const int32_t& aShellItemHeight) {
+ NS_ENSURE_TRUE(mFrameElement, IPC_OK());
+
+ nsCOMPtr<nsIDocShell> docShell = mFrameElement->OwnerDoc()->GetDocShell();
+ NS_ENSURE_TRUE(docShell, IPC_OK());
+
+ nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
+ nsresult rv = docShell->GetTreeOwner(getter_AddRefs(treeOwner));
+ NS_ENSURE_SUCCESS(rv, IPC_OK());
+
+ int32_t width = aWidth;
+ int32_t height = aHeight;
+
+ if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX) {
+ width = mDimensions.width;
+ }
+
+ if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY) {
+ height = mDimensions.height;
+ }
+
+ nsCOMPtr<nsIAppWindow> appWin(do_GetInterface(treeOwner));
+ NS_ENSURE_TRUE(appWin, IPC_OK());
+ appWin->SizeShellToWithLimit(width, height, aShellItemWidth,
+ aShellItemHeight);
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvDropLinks(
+ nsTArray<nsString>&& aLinks) {
+ nsCOMPtr<nsIBrowser> browser =
+ mFrameElement ? mFrameElement->AsBrowser() : nullptr;
+ if (browser) {
+ // Verify that links have not been modified by the child. If links have
+ // not been modified then it's safe to load those links using the
+ // SystemPrincipal. If they have been modified by web content, then
+ // we use a NullPrincipal which still allows to load web links.
+ bool loadUsingSystemPrincipal = true;
+ if (aLinks.Length() != mVerifyDropLinks.Length()) {
+ loadUsingSystemPrincipal = false;
+ }
+ for (uint32_t i = 0; i < aLinks.Length(); i++) {
+ if (loadUsingSystemPrincipal) {
+ if (!aLinks[i].Equals(mVerifyDropLinks[i])) {
+ loadUsingSystemPrincipal = false;
+ }
+ }
+ }
+ mVerifyDropLinks.Clear();
+ nsCOMPtr<nsIPrincipal> triggeringPrincipal;
+ if (loadUsingSystemPrincipal) {
+ triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
+ } else {
+ triggeringPrincipal = NullPrincipal::CreateWithoutOriginAttributes();
+ }
+ browser->DropLinks(aLinks, triggeringPrincipal);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvEvent(const RemoteDOMEvent& aEvent) {
+ RefPtr<Event> event = aEvent.mEvent;
+ NS_ENSURE_TRUE(event, IPC_OK());
+
+ RefPtr<EventTarget> target = mFrameElement;
+ NS_ENSURE_TRUE(target, IPC_OK());
+
+ event->SetOwner(target);
+
+ target->DispatchEvent(*event);
+ return IPC_OK();
+}
+
+bool BrowserParent::SendLoadRemoteScript(const nsString& aURL,
+ const bool& aRunInGlobalScope) {
+ if (mCreatingWindow) {
+ mDelayedFrameScripts.AppendElement(
+ FrameScriptInfo(aURL, aRunInGlobalScope));
+ return true;
+ }
+
+ MOZ_ASSERT(mDelayedFrameScripts.IsEmpty());
+ return PBrowserParent::SendLoadRemoteScript(aURL, aRunInGlobalScope);
+}
+
+void BrowserParent::LoadURL(nsDocShellLoadState* aLoadState) {
+ MOZ_ASSERT(aLoadState);
+ MOZ_ASSERT(aLoadState->URI());
+ if (mIsDestroyed) {
+ return;
+ }
+ nsCString spec;
+ aLoadState->URI()->GetSpec(spec);
+ if (mCreatingWindow) {
+ // Don't send the message if the child wants to load its own URL.
+ return;
+ }
+
+ Unused << SendLoadURL(aLoadState, GetShowInfo());
+}
+
+void BrowserParent::ResumeLoad(uint64_t aPendingSwitchID) {
+ MOZ_ASSERT(aPendingSwitchID != 0);
+
+ if (NS_WARN_IF(mIsDestroyed)) {
+ return;
+ }
+
+ Unused << SendResumeLoad(aPendingSwitchID, GetShowInfo());
+}
+
+void BrowserParent::InitRendering() {
+ if (mRemoteLayerTreeOwner.IsInitialized()) {
+ return;
+ }
+ mRemoteLayerTreeOwner.Initialize(this);
+
+ layers::LayersId layersId = mRemoteLayerTreeOwner.GetLayersId();
+ AddBrowserParentToTable(layersId, this);
+
+ RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
+ if (frameLoader) {
+ nsIFrame* frame = frameLoader->GetPrimaryFrameOfOwningContent();
+ if (frame) {
+ frame->InvalidateFrame();
+ }
+ }
+
+ TextureFactoryIdentifier textureFactoryIdentifier;
+ mRemoteLayerTreeOwner.GetTextureFactoryIdentifier(&textureFactoryIdentifier);
+ Unused << SendInitRendering(textureFactoryIdentifier, layersId,
+ mRemoteLayerTreeOwner.GetCompositorOptions(),
+ mRemoteLayerTreeOwner.IsLayersConnected());
+
+ RefPtr<nsIWidget> widget = GetTopLevelWidget();
+ if (widget) {
+ ScreenIntMargin safeAreaInsets = widget->GetSafeAreaInsets();
+ Unused << SendSafeAreaInsetsChanged(safeAreaInsets);
+ }
+
+#if defined(MOZ_WIDGET_ANDROID)
+ MOZ_ASSERT(widget);
+
+ Unused << SendDynamicToolbarMaxHeightChanged(
+ widget->GetDynamicToolbarMaxHeight());
+#endif
+}
+
+bool BrowserParent::AttachLayerManager() {
+ return !!mRemoteLayerTreeOwner.AttachLayerManager();
+}
+
+void BrowserParent::MaybeShowFrame() {
+ RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
+ if (!frameLoader) {
+ return;
+ }
+ frameLoader->MaybeShowFrame();
+}
+
+bool BrowserParent::Show(const OwnerShowInfo& aOwnerInfo) {
+ mDimensions = aOwnerInfo.size();
+ if (mIsDestroyed) {
+ return false;
+ }
+
+ MOZ_ASSERT(mRemoteLayerTreeOwner.IsInitialized());
+ if (!mRemoteLayerTreeOwner.AttachLayerManager()) {
+ return false;
+ }
+
+ mSizeMode = aOwnerInfo.sizeMode();
+ Unused << SendShow(GetShowInfo(), aOwnerInfo);
+ return true;
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSetDimensions(
+ const uint32_t& aFlags, const int32_t& aX, const int32_t& aY,
+ const int32_t& aCx, const int32_t& aCy, const double& aScale) {
+ MOZ_ASSERT(!(aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER),
+ "We should never see DIM_FLAGS_SIZE_INNER here!");
+
+ NS_ENSURE_TRUE(mFrameElement, IPC_OK());
+ nsCOMPtr<nsIDocShell> docShell = mFrameElement->OwnerDoc()->GetDocShell();
+ NS_ENSURE_TRUE(docShell, IPC_OK());
+ nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
+ docShell->GetTreeOwner(getter_AddRefs(treeOwner));
+ nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = do_QueryInterface(treeOwner);
+ NS_ENSURE_TRUE(treeOwnerAsWin, IPC_OK());
+
+ // We only care about the parameters that actually changed, see more details
+ // in `BrowserChild::SetDimensions()`.
+ // Note that `BrowserChild::SetDimensions()` may be called before receiving
+ // our `SendUIResolutionChanged()` call. Therefore, if given each cordinate
+ // shouldn't be ignored, we need to recompute it if DPI has been changed.
+ // And also note that don't use `mDefaultScale.scale` here since it may be
+ // different from the result of `GetUnscaledDevicePixelsPerCSSPixel()`.
+ double currentScale;
+ treeOwnerAsWin->GetUnscaledDevicePixelsPerCSSPixel(&currentScale);
+
+ int32_t x = aX;
+ int32_t y = aY;
+ if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) {
+ if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_X) {
+ int32_t unused;
+ treeOwnerAsWin->GetPosition(&x, &unused);
+ } else if (aScale != currentScale) {
+ x = x * currentScale / aScale;
+ }
+
+ if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_Y) {
+ int32_t unused;
+ treeOwnerAsWin->GetPosition(&unused, &y);
+ } else if (aScale != currentScale) {
+ y = y * currentScale / aScale;
+ }
+ }
+
+ int32_t cx = aCx;
+ int32_t cy = aCy;
+ if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER) {
+ if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CX) {
+ int32_t unused;
+ treeOwnerAsWin->GetSize(&cx, &unused);
+ } else if (aScale != currentScale) {
+ cx = cx * currentScale / aScale;
+ }
+
+ if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY) {
+ int32_t unused;
+ treeOwnerAsWin->GetSize(&unused, &cy);
+ } else if (aScale != currentScale) {
+ cy = cy * currentScale / aScale;
+ }
+ }
+
+ if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION &&
+ aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER) {
+ treeOwnerAsWin->SetPositionAndSize(x, y, cx, cy, nsIBaseWindow::eRepaint);
+ return IPC_OK();
+ }
+
+ if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) {
+ treeOwnerAsWin->SetPosition(x, y);
+ mUpdatedDimensions = false;
+ UpdatePosition();
+ return IPC_OK();
+ }
+
+ if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER) {
+ treeOwnerAsWin->SetSize(cx, cy, true);
+ return IPC_OK();
+ }
+
+ MOZ_ASSERT(false, "Unknown flags!");
+ return IPC_FAIL_NO_REASON(this);
+}
+
+nsresult BrowserParent::UpdatePosition() {
+ RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
+ if (!frameLoader) {
+ return NS_OK;
+ }
+ nsIntRect windowDims;
+ NS_ENSURE_SUCCESS(frameLoader->GetWindowDimensions(windowDims),
+ NS_ERROR_FAILURE);
+ UpdateDimensions(windowDims, mDimensions);
+ return NS_OK;
+}
+
+void BrowserParent::UpdateDimensions(const nsIntRect& rect,
+ const ScreenIntSize& size) {
+ if (mIsDestroyed) {
+ return;
+ }
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (!widget) {
+ NS_WARNING("No widget found in BrowserParent::UpdateDimensions");
+ return;
+ }
+
+ hal::ScreenConfiguration config;
+ hal::GetCurrentScreenConfiguration(&config);
+ hal::ScreenOrientation orientation = config.orientation();
+ LayoutDeviceIntPoint clientOffset = GetClientOffset();
+ LayoutDeviceIntPoint chromeOffset = !GetBrowserBridgeParent()
+ ? -GetChildProcessOffset()
+ : LayoutDeviceIntPoint();
+
+ if (!mUpdatedDimensions || mOrientation != orientation ||
+ mDimensions != size || !mRect.IsEqualEdges(rect) ||
+ clientOffset != mClientOffset || chromeOffset != mChromeOffset) {
+ mUpdatedDimensions = true;
+ mRect = rect;
+ mDimensions = size;
+ mOrientation = orientation;
+ mClientOffset = clientOffset;
+ mChromeOffset = chromeOffset;
+
+ Unused << SendUpdateDimensions(GetDimensionInfo());
+ }
+}
+
+DimensionInfo BrowserParent::GetDimensionInfo() {
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ MOZ_ASSERT(widget);
+ CSSToLayoutDeviceScale widgetScale = widget->GetDefaultScale();
+
+ LayoutDeviceIntRect devicePixelRect = ViewAs<LayoutDevicePixel>(
+ mRect, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
+ LayoutDeviceIntSize devicePixelSize = ViewAs<LayoutDevicePixel>(
+ mDimensions, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
+
+ CSSRect unscaledRect = devicePixelRect / widgetScale;
+ CSSSize unscaledSize = devicePixelSize / widgetScale;
+ DimensionInfo di(unscaledRect, unscaledSize, mOrientation, mClientOffset,
+ mChromeOffset);
+ return di;
+}
+
+void BrowserParent::SizeModeChanged(const nsSizeMode& aSizeMode) {
+ if (!mIsDestroyed && aSizeMode != mSizeMode) {
+ mSizeMode = aSizeMode;
+ Unused << SendSizeModeChanged(aSizeMode);
+ }
+}
+
+#if defined(MOZ_WIDGET_ANDROID)
+void BrowserParent::DynamicToolbarMaxHeightChanged(ScreenIntCoord aHeight) {
+ if (!mIsDestroyed) {
+ Unused << SendDynamicToolbarMaxHeightChanged(aHeight);
+ }
+}
+
+void BrowserParent::DynamicToolbarOffsetChanged(ScreenIntCoord aOffset) {
+ if (!mIsDestroyed) {
+ Unused << SendDynamicToolbarOffsetChanged(aOffset);
+ }
+}
+#endif
+
+void BrowserParent::HandleAccessKey(const WidgetKeyboardEvent& aEvent,
+ nsTArray<uint32_t>& aCharCodes) {
+ if (!mIsDestroyed) {
+ // Note that we don't need to mark aEvent is posted to a remote process
+ // because the event may be dispatched to it as normal keyboard event.
+ // Therefore, we should use local copy to send it.
+ WidgetKeyboardEvent localEvent(aEvent);
+ Unused << SendHandleAccessKey(localEvent, aCharCodes);
+ }
+}
+
+void BrowserParent::Activate(uint64_t aActionId) {
+ LOGBROWSERFOCUS(("Activate %p", this));
+ if (!mIsDestroyed) {
+ SetTopLevelWebFocus(this); // Intentionally inside "if"
+ Unused << SendActivate(aActionId);
+ }
+}
+
+void BrowserParent::Deactivate(bool aWindowLowering, uint64_t aActionId) {
+ LOGBROWSERFOCUS(("Deactivate %p", this));
+ if (!aWindowLowering) {
+ UnsetTopLevelWebFocus(this); // Intentionally outside the next "if"
+ }
+ if (!mIsDestroyed) {
+ Unused << SendDeactivate(aActionId);
+ }
+}
+
+#ifdef ACCESSIBILITY
+a11y::PDocAccessibleParent* BrowserParent::AllocPDocAccessibleParent(
+ PDocAccessibleParent* aParent, const uint64_t&, const uint32_t&,
+ const IAccessibleHolder&) {
+ // Reference freed in DeallocPDocAccessibleParent.
+ return do_AddRef(new a11y::DocAccessibleParent()).take();
+}
+
+bool BrowserParent::DeallocPDocAccessibleParent(PDocAccessibleParent* aParent) {
+ // Free reference from AllocPDocAccessibleParent.
+ static_cast<a11y::DocAccessibleParent*>(aParent)->Release();
+ return true;
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvPDocAccessibleConstructor(
+ PDocAccessibleParent* aDoc, PDocAccessibleParent* aParentDoc,
+ const uint64_t& aParentID, const uint32_t& aMsaaID,
+ const IAccessibleHolder& aDocCOMProxy) {
+ auto doc = static_cast<a11y::DocAccessibleParent*>(aDoc);
+
+ // If this tab is already shutting down just mark the new actor as shutdown
+ // and ignore it. When the tab actor is destroyed it will be too.
+ if (mIsDestroyed) {
+ doc->MarkAsShutdown();
+ return IPC_OK();
+ }
+
+ if (aParentDoc) {
+ // A document should never directly be the parent of another document.
+ // There should always be an outer doc accessible child of the outer
+ // document containing the child.
+ MOZ_ASSERT(aParentID);
+ if (!aParentID) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ auto parentDoc = static_cast<a11y::DocAccessibleParent*>(aParentDoc);
+ mozilla::ipc::IPCResult added = parentDoc->AddChildDoc(doc, aParentID);
+ if (!added) {
+# ifdef DEBUG
+ return added;
+# else
+ return IPC_OK();
+# endif
+ }
+
+# ifdef XP_WIN
+ MOZ_ASSERT(aDocCOMProxy.IsNull());
+ a11y::WrapperFor(doc)->SetID(aMsaaID);
+ if (a11y::nsWinUtils::IsWindowEmulationStarted()) {
+ doc->SetEmulatedWindowHandle(parentDoc->GetEmulatedWindowHandle());
+ }
+# else
+ Unused << aDoc->SendConstructedInParentProcess();
+# endif
+
+ return IPC_OK();
+ }
+
+ if (GetBrowserBridgeParent()) {
+ // Iframe document rendered in a different process to its embedder.
+ // In this case, we don't get aParentDoc and aParentID.
+ MOZ_ASSERT(!aParentDoc && !aParentID);
+ doc->SetTopLevelInContentProcess();
+# ifdef XP_WIN
+ MOZ_ASSERT(!aDocCOMProxy.IsNull());
+ RefPtr<IAccessible> proxy(aDocCOMProxy.Get());
+ doc->SetCOMInterface(proxy);
+# endif
+ a11y::ProxyCreated(
+ doc, a11y::Interfaces::DOCUMENT | a11y::Interfaces::HYPERTEXT);
+# ifdef XP_WIN
+ // This *must* be called after ProxyCreated because WrapperFor will fail
+ // before that.
+ a11y::AccessibleWrap* wrapper = a11y::WrapperFor(doc);
+ MOZ_ASSERT(wrapper);
+ wrapper->SetID(aMsaaID);
+# endif
+ a11y::DocAccessibleParent* embedderDoc;
+ uint64_t embedderID;
+ Tie(embedderDoc, embedderID) = doc->GetRemoteEmbedder();
+ // It's possible the embedder accessible hasn't been set yet; e.g.
+ // a hidden iframe. In that case, embedderDoc will be null and this will
+ // be handled when the embedder is set.
+ if (embedderDoc) {
+ MOZ_ASSERT(embedderID);
+ mozilla::ipc::IPCResult added =
+ embedderDoc->AddChildDoc(doc, embedderID,
+ /* aCreating */ false);
+ if (!added) {
+# ifdef DEBUG
+ return added;
+# else
+ return IPC_OK();
+# endif
+ }
+ }
+ return IPC_OK();
+ } else {
+ // null aParentDoc means this document is at the top level in the child
+ // process. That means it makes no sense to get an id for an accessible
+ // that is its parent.
+ MOZ_ASSERT(!aParentID);
+ if (aParentID) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ doc->SetTopLevel();
+ a11y::DocManager::RemoteDocAdded(doc);
+# ifdef XP_WIN
+ a11y::WrapperFor(doc)->SetID(aMsaaID);
+ MOZ_ASSERT(!aDocCOMProxy.IsNull());
+
+ RefPtr<IAccessible> proxy(aDocCOMProxy.Get());
+ doc->SetCOMInterface(proxy);
+ doc->MaybeInitWindowEmulation();
+ if (a11y::Accessible* outerDoc = doc->OuterDocOfRemoteBrowser()) {
+ doc->SendParentCOMProxy(outerDoc);
+ }
+# endif
+ }
+ return IPC_OK();
+}
+#endif
+
+PFilePickerParent* BrowserParent::AllocPFilePickerParent(const nsString& aTitle,
+ const int16_t& aMode) {
+ return new FilePickerParent(aTitle, aMode);
+}
+
+bool BrowserParent::DeallocPFilePickerParent(PFilePickerParent* actor) {
+ delete actor;
+ return true;
+}
+
+IPCResult BrowserParent::RecvIndexedDBPermissionRequest(
+ nsIPrincipal* aPrincipal, IndexedDBPermissionRequestResolver&& aResolve) {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsCOMPtr<nsIPrincipal> principal(aPrincipal);
+ if (!principal) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ if (NS_WARN_IF(!mFrameElement)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ RefPtr<indexedDB::PermissionRequestHelper> actor =
+ new indexedDB::PermissionRequestHelper(mFrameElement, principal,
+ aResolve);
+
+ mozilla::Result permissionOrErr = actor->PromptIfNeeded();
+ if (permissionOrErr.isErr()) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ if (permissionOrErr.inspect() !=
+ indexedDB::PermissionRequestBase::kPermissionPrompt) {
+ aResolve(permissionOrErr.inspect());
+ }
+
+ return IPC_OK();
+}
+
+IPCResult BrowserParent::RecvNewWindowGlobal(
+ ManagedEndpoint<PWindowGlobalParent>&& aEndpoint,
+ const WindowGlobalInit& aInit) {
+ RefPtr<CanonicalBrowsingContext> browsingContext =
+ CanonicalBrowsingContext::Get(aInit.context().mBrowsingContextId);
+ if (!browsingContext) {
+ return IPC_FAIL(this, "Cannot create for missing BrowsingContext");
+ }
+ if (!aInit.principal()) {
+ return IPC_FAIL(this, "Cannot create without valid principal");
+ }
+
+ // Construct our new WindowGlobalParent, bind, and initialize it.
+ RefPtr<WindowGlobalParent> wgp =
+ WindowGlobalParent::CreateDisconnected(aInit);
+ BindPWindowGlobalEndpoint(std::move(aEndpoint), wgp);
+ wgp->Init();
+ return IPC_OK();
+}
+
+PVsyncParent* BrowserParent::AllocPVsyncParent() {
+ MOZ_ASSERT(!mVsyncParent);
+ mVsyncParent = new VsyncParent();
+ UpdateVsyncParentVsyncSource();
+ return mVsyncParent.get();
+}
+
+bool BrowserParent::DeallocPVsyncParent(PVsyncParent* aActor) {
+ MOZ_ASSERT(aActor);
+ mVsyncParent = nullptr;
+ return true;
+}
+
+void BrowserParent::UpdateVsyncParentVsyncSource() {
+ if (!mVsyncParent) {
+ return;
+ }
+
+ if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
+ mVsyncParent->UpdateVsyncSource(widget->GetVsyncSource());
+ }
+}
+
+void BrowserParent::SendMouseEvent(const nsAString& aType, float aX, float aY,
+ int32_t aButton, int32_t aClickCount,
+ int32_t aModifiers) {
+ if (!mIsDestroyed) {
+ Unused << PBrowserParent::SendMouseEvent(nsString(aType), aX, aY, aButton,
+ aClickCount, aModifiers);
+ }
+}
+
+void BrowserParent::MouseEnterIntoWidget() {
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (widget) {
+ // When we mouseenter the remote target, the remote target's cursor should
+ // become the current cursor. When we mouseexit, we stop.
+ mRemoteTargetSetsCursor = true;
+ if (mCursor != eCursorInvalid) {
+ widget->SetCursor(mCursor, mCustomCursor, mCustomCursorHotspotX,
+ mCustomCursorHotspotY);
+ }
+ }
+
+ // Mark that we have missed a mouse enter event, so that
+ // the next mouse event will create a replacement mouse
+ // enter event and send it to the child.
+ mIsMouseEnterIntoWidgetEventSuppressed = true;
+}
+
+void BrowserParent::SendRealMouseEvent(WidgetMouseEvent& aEvent) {
+ if (mIsDestroyed) {
+ return;
+ }
+
+ // XXXedgar, if the synthesized mouse events could deliver to the correct
+ // process directly (see
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1549355), we probably don't
+ // need to check mReason then.
+ if (aEvent.mReason == WidgetMouseEvent::eReal) {
+ if (aEvent.mMessage == eMouseExitFromWidget) {
+ // Since we are leaving this remote target, so don't need to update
+ // sLastMouseRemoteTarget, and if we are sLastMouseRemoteTarget, reset it
+ // to null.
+ BrowserParent::UnsetLastMouseRemoteTarget(this);
+ } else {
+ // Last remote target should not be changed without eMouseExitFromWidget.
+ MOZ_ASSERT_IF(sLastMouseRemoteTarget, sLastMouseRemoteTarget == this);
+ sLastMouseRemoteTarget = this;
+ }
+ }
+
+ aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
+
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (widget) {
+ // When we mouseenter the remote target, the remote target's cursor should
+ // become the current cursor. When we mouseexit, we stop.
+ if (eMouseEnterIntoWidget == aEvent.mMessage) {
+ mRemoteTargetSetsCursor = true;
+ if (mCursor != eCursorInvalid) {
+ widget->SetCursor(mCursor, mCustomCursor, mCustomCursorHotspotX,
+ mCustomCursorHotspotY);
+ }
+ } else if (eMouseExitFromWidget == aEvent.mMessage) {
+ mRemoteTargetSetsCursor = false;
+ }
+ }
+ if (!mIsReadyToHandleInputEvents) {
+ if (eMouseEnterIntoWidget == aEvent.mMessage) {
+ mIsMouseEnterIntoWidgetEventSuppressed = true;
+ } else if (eMouseExitFromWidget == aEvent.mMessage) {
+ mIsMouseEnterIntoWidgetEventSuppressed = false;
+ }
+ return;
+ }
+
+ ScrollableLayerGuid guid;
+ uint64_t blockId;
+ ApzAwareEventRoutingToChild(&guid, &blockId, nullptr);
+
+ bool isInputPriorityEventEnabled = Manager()->IsInputPriorityEventEnabled();
+
+ if (mIsMouseEnterIntoWidgetEventSuppressed) {
+ // In the case that the BrowserParent suppressed the eMouseEnterWidget event
+ // due to its corresponding BrowserChild wasn't ready to handle it, we have
+ // to resend it when the BrowserChild is ready.
+ mIsMouseEnterIntoWidgetEventSuppressed = false;
+ WidgetMouseEvent localEvent(aEvent);
+ localEvent.mMessage = eMouseEnterIntoWidget;
+ DebugOnly<bool> ret =
+ isInputPriorityEventEnabled
+ ? SendRealMouseButtonEvent(localEvent, guid, blockId)
+ : SendNormalPriorityRealMouseButtonEvent(localEvent, guid, blockId);
+ NS_WARNING_ASSERTION(
+ ret, "SendRealMouseButtonEvent(eMouseEnterIntoWidget) failed");
+ MOZ_ASSERT(!ret || localEvent.HasBeenPostedToRemoteProcess());
+ }
+
+ if (eMouseMove == aEvent.mMessage) {
+ if (aEvent.mReason == WidgetMouseEvent::eSynthesized) {
+ DebugOnly<bool> ret =
+ isInputPriorityEventEnabled
+ ? SendSynthMouseMoveEvent(aEvent, guid, blockId)
+ : SendNormalPrioritySynthMouseMoveEvent(aEvent, guid, blockId);
+ NS_WARNING_ASSERTION(ret, "SendSynthMouseMoveEvent() failed");
+ MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
+ return;
+ }
+
+ if (!aEvent.mFlags.mIsSynthesizedForTests) {
+ DebugOnly<bool> ret =
+ isInputPriorityEventEnabled
+ ? SendRealMouseMoveEvent(aEvent, guid, blockId)
+ : SendNormalPriorityRealMouseMoveEvent(aEvent, guid, blockId);
+ NS_WARNING_ASSERTION(ret, "SendRealMouseMoveEvent() failed");
+ MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
+ return;
+ }
+
+ DebugOnly<bool> ret =
+ isInputPriorityEventEnabled
+ ? SendRealMouseMoveEventForTests(aEvent, guid, blockId)
+ : SendNormalPriorityRealMouseMoveEventForTests(aEvent, guid,
+ blockId);
+ NS_WARNING_ASSERTION(ret, "SendRealMouseMoveEventForTests() failed");
+ MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
+ return;
+ }
+
+ DebugOnly<bool> ret =
+ isInputPriorityEventEnabled
+ ? SendRealMouseButtonEvent(aEvent, guid, blockId)
+ : SendNormalPriorityRealMouseButtonEvent(aEvent, guid, blockId);
+ NS_WARNING_ASSERTION(ret, "SendRealMouseButtonEvent() failed");
+ MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
+}
+
+LayoutDeviceToCSSScale BrowserParent::GetLayoutDeviceToCSSScale() {
+ Document* doc = (mFrameElement ? mFrameElement->OwnerDoc() : nullptr);
+ nsPresContext* ctx = (doc ? doc->GetPresContext() : nullptr);
+ return LayoutDeviceToCSSScale(
+ ctx ? (float)ctx->AppUnitsPerDevPixel() / AppUnitsPerCSSPixel() : 0.0f);
+}
+
+bool BrowserParent::QueryDropLinksForVerification() {
+ // Before sending the dragEvent, we query the links being dragged and
+ // store them on the parent, to make sure the child can not modify links.
+ nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
+ if (!dragSession) {
+ NS_WARNING("No dragSession to query links for verification");
+ return false;
+ }
+
+ RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
+ if (!initialDataTransfer) {
+ NS_WARNING("No initialDataTransfer to query links for verification");
+ return false;
+ }
+
+ nsCOMPtr<nsIDroppedLinkHandler> dropHandler =
+ do_GetService("@mozilla.org/content/dropped-link-handler;1");
+ if (!dropHandler) {
+ NS_WARNING("No dropHandler to query links for verification");
+ return false;
+ }
+
+ // No more than one drop event can happen simultaneously; reset the link
+ // verification array and store all links that are being dragged.
+ mVerifyDropLinks.Clear();
+
+ nsTArray<RefPtr<nsIDroppedLinkItem>> droppedLinkItems;
+ dropHandler->QueryLinks(initialDataTransfer, droppedLinkItems);
+
+ // Since the entire event is cancelled if one of the links is invalid,
+ // we can store all links on the parent side without any prior
+ // validation checks.
+ nsresult rv = NS_OK;
+ for (nsIDroppedLinkItem* item : droppedLinkItems) {
+ nsString tmp;
+ rv = item->GetUrl(tmp);
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Failed to query url for verification");
+ break;
+ }
+ mVerifyDropLinks.AppendElement(tmp);
+
+ rv = item->GetName(tmp);
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Failed to query name for verification");
+ break;
+ }
+ mVerifyDropLinks.AppendElement(tmp);
+
+ rv = item->GetType(tmp);
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Failed to query type for verification");
+ break;
+ }
+ mVerifyDropLinks.AppendElement(tmp);
+ }
+ if (NS_FAILED(rv)) {
+ mVerifyDropLinks.Clear();
+ return false;
+ }
+ return true;
+}
+
+void BrowserParent::SendRealDragEvent(WidgetDragEvent& aEvent,
+ uint32_t aDragAction,
+ uint32_t aDropEffect,
+ nsIPrincipal* aPrincipal,
+ nsIContentSecurityPolicy* aCsp) {
+ if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
+ return;
+ }
+ MOZ_ASSERT(!Manager()->IsInputPriorityEventEnabled());
+ aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
+ if (aEvent.mMessage == eDrop) {
+ if (!QueryDropLinksForVerification()) {
+ return;
+ }
+ }
+ DebugOnly<bool> ret = PBrowserParent::SendRealDragEvent(
+ aEvent, aDragAction, aDropEffect, aPrincipal, aCsp);
+ NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealDragEvent() failed");
+ MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
+}
+
+void BrowserParent::SendMouseWheelEvent(WidgetWheelEvent& aEvent) {
+ if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
+ return;
+ }
+
+ ScrollableLayerGuid guid;
+ uint64_t blockId;
+ ApzAwareEventRoutingToChild(&guid, &blockId, nullptr);
+ aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
+ DebugOnly<bool> ret =
+ Manager()->IsInputPriorityEventEnabled()
+ ? PBrowserParent::SendMouseWheelEvent(aEvent, guid, blockId)
+ : PBrowserParent::SendNormalPriorityMouseWheelEvent(aEvent, guid,
+ blockId);
+
+ NS_WARNING_ASSERTION(ret, "PBrowserParent::SendMouseWheelEvent() failed");
+ MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvDispatchWheelEvent(
+ const mozilla::WidgetWheelEvent& aEvent) {
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (!widget) {
+ return IPC_OK();
+ }
+
+ WidgetWheelEvent localEvent(aEvent);
+ localEvent.mWidget = widget;
+ localEvent.mRefPoint = TransformChildToParent(localEvent.mRefPoint);
+
+ widget->DispatchInputEvent(&localEvent);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvDispatchMouseEvent(
+ const mozilla::WidgetMouseEvent& aEvent) {
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (!widget) {
+ return IPC_OK();
+ }
+
+ WidgetMouseEvent localEvent(aEvent);
+ localEvent.mWidget = widget;
+ localEvent.mRefPoint = TransformChildToParent(localEvent.mRefPoint);
+
+ widget->DispatchInputEvent(&localEvent);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvDispatchKeyboardEvent(
+ const mozilla::WidgetKeyboardEvent& aEvent) {
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (!widget) {
+ return IPC_OK();
+ }
+
+ WidgetKeyboardEvent localEvent(aEvent);
+ localEvent.mWidget = widget;
+ localEvent.mRefPoint = TransformChildToParent(localEvent.mRefPoint);
+
+ widget->DispatchInputEvent(&localEvent);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvRequestNativeKeyBindings(
+ const uint32_t& aType, const WidgetKeyboardEvent& aEvent,
+ nsTArray<CommandInt>* aCommands) {
+ MOZ_ASSERT(aCommands);
+ MOZ_ASSERT(aCommands->IsEmpty());
+
+ nsIWidget::NativeKeyBindingsType keyBindingsType =
+ static_cast<nsIWidget::NativeKeyBindingsType>(aType);
+ switch (keyBindingsType) {
+ case nsIWidget::NativeKeyBindingsForSingleLineEditor:
+ case nsIWidget::NativeKeyBindingsForMultiLineEditor:
+ case nsIWidget::NativeKeyBindingsForRichTextEditor:
+ break;
+ default:
+ return IPC_FAIL(this, "Invalid aType value");
+ }
+
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (!widget) {
+ return IPC_OK();
+ }
+
+ WidgetKeyboardEvent localEvent(aEvent);
+ localEvent.mWidget = widget;
+
+ if (NS_FAILED(widget->AttachNativeKeyEvent(localEvent))) {
+ return IPC_OK();
+ }
+
+ if (localEvent.InitEditCommandsFor(keyBindingsType)) {
+ *aCommands = localEvent.EditCommandsConstRef(keyBindingsType).Clone();
+ }
+
+ return IPC_OK();
+}
+
+class SynthesizedEventObserver : public nsIObserver {
+ NS_DECL_ISUPPORTS
+
+ public:
+ SynthesizedEventObserver(BrowserParent* aBrowserParent,
+ const uint64_t& aObserverId)
+ : mBrowserParent(aBrowserParent), mObserverId(aObserverId) {
+ MOZ_ASSERT(mBrowserParent);
+ }
+
+ NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
+ const char16_t* aData) override {
+ if (!mBrowserParent || !mObserverId) {
+ // We already sent the notification, or we don't actually need to
+ // send any notification at all.
+ return NS_OK;
+ }
+
+ if (mBrowserParent->IsDestroyed()) {
+ // If this happens it's probably a bug in the test that's triggering this.
+ NS_WARNING(
+ "BrowserParent was unexpectedly destroyed during event "
+ "synthesization!");
+ } else if (!mBrowserParent->SendNativeSynthesisResponse(
+ mObserverId, nsCString(aTopic))) {
+ NS_WARNING("Unable to send native event synthesization response!");
+ }
+ // Null out browserParent to indicate we already sent the response
+ mBrowserParent = nullptr;
+ return NS_OK;
+ }
+
+ private:
+ virtual ~SynthesizedEventObserver() = default;
+
+ RefPtr<BrowserParent> mBrowserParent;
+ uint64_t mObserverId;
+};
+
+NS_IMPL_ISUPPORTS(SynthesizedEventObserver, nsIObserver)
+
+class MOZ_STACK_CLASS AutoSynthesizedEventResponder {
+ public:
+ AutoSynthesizedEventResponder(BrowserParent* aBrowserParent,
+ const uint64_t& aObserverId, const char* aTopic)
+ : mObserver(new SynthesizedEventObserver(aBrowserParent, aObserverId)),
+ mTopic(aTopic) {}
+
+ ~AutoSynthesizedEventResponder() {
+ // This may be a no-op if the observer already sent a response.
+ mObserver->Observe(nullptr, mTopic, nullptr);
+ }
+
+ nsIObserver* GetObserver() { return mObserver; }
+
+ private:
+ nsCOMPtr<nsIObserver> mObserver;
+ const char* mTopic;
+};
+
+mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeKeyEvent(
+ const int32_t& aNativeKeyboardLayout, const int32_t& aNativeKeyCode,
+ const uint32_t& aModifierFlags, const nsString& aCharacters,
+ const nsString& aUnmodifiedCharacters, const uint64_t& aObserverId) {
+ AutoSynthesizedEventResponder responder(this, aObserverId, "keyevent");
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (widget) {
+ widget->SynthesizeNativeKeyEvent(
+ aNativeKeyboardLayout, aNativeKeyCode, aModifierFlags, aCharacters,
+ aUnmodifiedCharacters, responder.GetObserver());
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeMouseEvent(
+ const LayoutDeviceIntPoint& aPoint, const uint32_t& aNativeMessage,
+ const uint32_t& aModifierFlags, const uint64_t& aObserverId) {
+ AutoSynthesizedEventResponder responder(this, aObserverId, "mouseevent");
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (widget) {
+ widget->SynthesizeNativeMouseEvent(aPoint, aNativeMessage, aModifierFlags,
+ responder.GetObserver());
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeMouseMove(
+ const LayoutDeviceIntPoint& aPoint, const uint64_t& aObserverId) {
+ AutoSynthesizedEventResponder responder(this, aObserverId, "mousemove");
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (widget) {
+ widget->SynthesizeNativeMouseMove(aPoint, responder.GetObserver());
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeMouseScrollEvent(
+ const LayoutDeviceIntPoint& aPoint, const uint32_t& aNativeMessage,
+ const double& aDeltaX, const double& aDeltaY, const double& aDeltaZ,
+ const uint32_t& aModifierFlags, const uint32_t& aAdditionalFlags,
+ const uint64_t& aObserverId) {
+ AutoSynthesizedEventResponder responder(this, aObserverId,
+ "mousescrollevent");
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (widget) {
+ widget->SynthesizeNativeMouseScrollEvent(
+ aPoint, aNativeMessage, aDeltaX, aDeltaY, aDeltaZ, aModifierFlags,
+ aAdditionalFlags, responder.GetObserver());
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeTouchPoint(
+ const uint32_t& aPointerId, const TouchPointerState& aPointerState,
+ const LayoutDeviceIntPoint& aPoint, const double& aPointerPressure,
+ const uint32_t& aPointerOrientation, const uint64_t& aObserverId) {
+ AutoSynthesizedEventResponder responder(this, aObserverId, "touchpoint");
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (widget) {
+ widget->SynthesizeNativeTouchPoint(aPointerId, aPointerState, aPoint,
+ aPointerPressure, aPointerOrientation,
+ responder.GetObserver());
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSynthesizeNativeTouchTap(
+ const LayoutDeviceIntPoint& aPoint, const bool& aLongTap,
+ const uint64_t& aObserverId) {
+ AutoSynthesizedEventResponder responder(this, aObserverId, "touchtap");
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (widget) {
+ widget->SynthesizeNativeTouchTap(aPoint, aLongTap, responder.GetObserver());
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvClearNativeTouchSequence(
+ const uint64_t& aObserverId) {
+ AutoSynthesizedEventResponder responder(this, aObserverId, "cleartouch");
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (widget) {
+ widget->ClearNativeTouchSequence(responder.GetObserver());
+ }
+ return IPC_OK();
+}
+
+void BrowserParent::SendRealKeyEvent(WidgetKeyboardEvent& aEvent) {
+ if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
+ return;
+ }
+ aEvent.mRefPoint = TransformParentToChild(aEvent.mRefPoint);
+
+ if (aEvent.mMessage == eKeyPress) {
+ // XXX Should we do this only when input context indicates an editor having
+ // focus and the key event won't cause inputting text?
+ aEvent.InitAllEditCommands();
+ } else {
+ aEvent.PreventNativeKeyBindings();
+ }
+ DebugOnly<bool> ret =
+ Manager()->IsInputPriorityEventEnabled()
+ ? PBrowserParent::SendRealKeyEvent(aEvent)
+ : PBrowserParent::SendNormalPriorityRealKeyEvent(aEvent);
+
+ NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealKeyEvent() failed");
+ MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
+}
+
+void BrowserParent::SendRealTouchEvent(WidgetTouchEvent& aEvent) {
+ if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
+ return;
+ }
+
+ // PresShell::HandleEventInternal adds touches on touch end/cancel. This
+ // confuses remote content and the panning and zooming logic into thinking
+ // that the added touches are part of the touchend/cancel, when actually
+ // they're not.
+ if (aEvent.mMessage == eTouchEnd || aEvent.mMessage == eTouchCancel) {
+ aEvent.mTouches.RemoveElementsBy(
+ [](const auto& touch) { return !touch->mChanged; });
+ }
+
+ APZData apzData;
+ ApzAwareEventRoutingToChild(&apzData.guid, &apzData.blockId,
+ &apzData.apzResponse);
+
+ if (mIsDestroyed) {
+ return;
+ }
+
+ for (uint32_t i = 0; i < aEvent.mTouches.Length(); i++) {
+ aEvent.mTouches[i]->mRefPoint =
+ TransformParentToChild(aEvent.mTouches[i]->mRefPoint);
+ }
+
+ static uint32_t sConsecutiveTouchMoveCount = 0;
+ if (aEvent.mMessage == eTouchMove) {
+ ++sConsecutiveTouchMoveCount;
+ SendRealTouchMoveEvent(aEvent, apzData, sConsecutiveTouchMoveCount);
+ return;
+ }
+
+ sConsecutiveTouchMoveCount = 0;
+ DebugOnly<bool> ret =
+ Manager()->IsInputPriorityEventEnabled()
+ ? PBrowserParent::SendRealTouchEvent(
+ aEvent, apzData.guid, apzData.blockId, apzData.apzResponse)
+ : PBrowserParent::SendNormalPriorityRealTouchEvent(
+ aEvent, apzData.guid, apzData.blockId, apzData.apzResponse);
+
+ NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealTouchEvent() failed");
+ MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
+}
+
+void BrowserParent::SendRealTouchMoveEvent(
+ WidgetTouchEvent& aEvent, APZData& aAPZData,
+ uint32_t aConsecutiveTouchMoveCount) {
+ // Touchmove handling is complicated, since IPC compression should be used
+ // only when there are consecutive touch objects for the same touch on the
+ // same BrowserParent. IPC compression can be disabled by switching to
+ // different IPC message.
+ static bool sIPCMessageType1 = true;
+ static TabId sLastTargetBrowserParent(0);
+ static Maybe<APZData> sPreviousAPZData;
+ // Artificially limit max touch points to 10. That should be in practise
+ // more than enough.
+ const uint32_t kMaxTouchMoveIdentifiers = 10;
+ static Maybe<int32_t> sLastTouchMoveIdentifiers[kMaxTouchMoveIdentifiers];
+
+ // Returns true if aIdentifiers contains all the touches in
+ // sLastTouchMoveIdentifiers.
+ auto LastTouchMoveIdentifiersContainedIn =
+ [&](const nsTArray<int32_t>& aIdentifiers) -> bool {
+ for (Maybe<int32_t>& entry : sLastTouchMoveIdentifiers) {
+ if (entry.isSome() && !aIdentifiers.Contains(entry.value())) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ // Cache touch identifiers in sLastTouchMoveIdentifiers array to be used
+ // when checking whether compression can be done for the next touchmove.
+ auto SetLastTouchMoveIdentifiers =
+ [&](const nsTArray<int32_t>& aIdentifiers) {
+ for (Maybe<int32_t>& entry : sLastTouchMoveIdentifiers) {
+ entry.reset();
+ }
+
+ MOZ_ASSERT(aIdentifiers.Length() <= kMaxTouchMoveIdentifiers);
+ for (uint32_t j = 0; j < aIdentifiers.Length(); ++j) {
+ sLastTouchMoveIdentifiers[j].emplace(aIdentifiers[j]);
+ }
+ };
+
+ AutoTArray<int32_t, kMaxTouchMoveIdentifiers> changedTouches;
+ bool preventCompression = !StaticPrefs::dom_events_compress_touchmove() ||
+ // Ensure the very first touchmove isn't overridden
+ // by the second one, so that web pages can get
+ // accurate coordinates for the first touchmove.
+ aConsecutiveTouchMoveCount < 3 ||
+ sPreviousAPZData.isNothing() ||
+ sPreviousAPZData.value() != aAPZData ||
+ sLastTargetBrowserParent != GetTabId() ||
+ aEvent.mTouches.Length() > kMaxTouchMoveIdentifiers;
+
+ if (!preventCompression) {
+ for (RefPtr<Touch>& touch : aEvent.mTouches) {
+ if (touch->mChanged) {
+ changedTouches.AppendElement(touch->mIdentifier);
+ }
+ }
+
+ // Prevent compression if the new event has fewer or different touches
+ // than the old one.
+ preventCompression = !LastTouchMoveIdentifiersContainedIn(changedTouches);
+ }
+
+ if (preventCompression) {
+ sIPCMessageType1 = !sIPCMessageType1;
+ }
+
+ // Update the last touch move identifiers always, so that when the next
+ // event comes in, the new identifiers can be compared to the old ones.
+ // If the pref is disabled, this just does a quick small loop.
+ SetLastTouchMoveIdentifiers(changedTouches);
+ sPreviousAPZData.reset();
+ sPreviousAPZData.emplace(aAPZData);
+ sLastTargetBrowserParent = GetTabId();
+
+ DebugOnly<bool> ret = true;
+ if (sIPCMessageType1) {
+ ret =
+ Manager()->IsInputPriorityEventEnabled()
+ ? PBrowserParent::SendRealTouchMoveEvent(
+ aEvent, aAPZData.guid, aAPZData.blockId, aAPZData.apzResponse)
+ : PBrowserParent::SendNormalPriorityRealTouchMoveEvent(
+ aEvent, aAPZData.guid, aAPZData.blockId,
+ aAPZData.apzResponse);
+ } else {
+ ret =
+ Manager()->IsInputPriorityEventEnabled()
+ ? PBrowserParent::SendRealTouchMoveEvent2(
+ aEvent, aAPZData.guid, aAPZData.blockId, aAPZData.apzResponse)
+ : PBrowserParent::SendNormalPriorityRealTouchMoveEvent2(
+ aEvent, aAPZData.guid, aAPZData.blockId,
+ aAPZData.apzResponse);
+ }
+
+ NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealTouchMoveEvent() failed");
+ MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
+}
+
+bool BrowserParent::SendHandleTap(TapType aType,
+ const LayoutDevicePoint& aPoint,
+ Modifiers aModifiers,
+ const ScrollableLayerGuid& aGuid,
+ uint64_t aInputBlockId) {
+ if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
+ return false;
+ }
+ if ((aType == TapType::eSingleTap || aType == TapType::eSecondTap)) {
+ if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
+ if (RefPtr<nsFrameLoader> frameLoader = GetFrameLoader()) {
+ if (RefPtr<Element> element = frameLoader->GetOwnerContent()) {
+ fm->SetFocus(element, nsIFocusManager::FLAG_BYMOUSE |
+ nsIFocusManager::FLAG_BYTOUCH |
+ nsIFocusManager::FLAG_NOSCROLL);
+ }
+ }
+ }
+ }
+ return Manager()->IsInputPriorityEventEnabled()
+ ? PBrowserParent::SendHandleTap(aType,
+ TransformParentToChild(aPoint),
+ aModifiers, aGuid, aInputBlockId)
+ : PBrowserParent::SendNormalPriorityHandleTap(
+ aType, TransformParentToChild(aPoint), aModifiers, aGuid,
+ aInputBlockId);
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSyncMessage(
+ const nsString& aMessage, const ClonedMessageData& aData,
+ nsTArray<StructuredCloneData>* aRetVal) {
+ AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("BrowserParent::RecvSyncMessage",
+ OTHER, aMessage);
+ MMPrinter::Print("BrowserParent::RecvSyncMessage", aMessage, aData);
+
+ StructuredCloneData data;
+ ipc::UnpackClonedMessageDataForParent(aData, data);
+
+ if (!ReceiveMessage(aMessage, true, &data, aRetVal)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvAsyncMessage(
+ const nsString& aMessage, const ClonedMessageData& aData) {
+ AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING("BrowserParent::RecvAsyncMessage",
+ OTHER, aMessage);
+ MMPrinter::Print("BrowserParent::RecvAsyncMessage", aMessage, aData);
+
+ StructuredCloneData data;
+ ipc::UnpackClonedMessageDataForParent(aData, data);
+
+ if (!ReceiveMessage(aMessage, false, &data, nullptr)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSetCursor(
+ const nsCursor& aCursor, const bool& aHasCustomCursor,
+ const nsCString& aCursorData, const uint32_t& aWidth,
+ const uint32_t& aHeight, const uint32_t& aStride,
+ const gfx::SurfaceFormat& aFormat, const uint32_t& aHotspotX,
+ const uint32_t& aHotspotY, const bool& aForce) {
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (!widget) {
+ return IPC_OK();
+ }
+
+ if (aForce) {
+ widget->ClearCachedCursor();
+ }
+
+ nsCOMPtr<imgIContainer> cursorImage;
+ if (aHasCustomCursor) {
+ if (aHeight * aStride != aCursorData.Length() ||
+ aStride < aWidth * gfx::BytesPerPixel(aFormat)) {
+ return IPC_FAIL(this, "Invalid custom cursor data");
+ }
+ const gfx::IntSize size(aWidth, aHeight);
+ RefPtr<gfx::DataSourceSurface> customCursor =
+ gfx::CreateDataSourceSurfaceFromData(
+ size, aFormat,
+ reinterpret_cast<const uint8_t*>(aCursorData.BeginReading()),
+ aStride);
+
+ RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(customCursor, size);
+ cursorImage = image::ImageOps::CreateFromDrawable(drawable);
+ }
+
+ mCursor = aCursor;
+ mCustomCursor = cursorImage;
+ mCustomCursorHotspotX = aHotspotX;
+ mCustomCursorHotspotY = aHotspotY;
+
+ if (!mRemoteTargetSetsCursor) {
+ return IPC_OK();
+ }
+
+ widget->SetCursor(aCursor, cursorImage, aHotspotX, aHotspotY);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSetLinkStatus(
+ const nsString& aStatus) {
+ nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow = GetXULBrowserWindow();
+ if (!xulBrowserWindow) {
+ return IPC_OK();
+ }
+
+ xulBrowserWindow->SetOverLink(aStatus);
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvShowTooltip(
+ const uint32_t& aX, const uint32_t& aY, const nsString& aTooltip,
+ const nsString& aDirection) {
+ nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow = GetXULBrowserWindow();
+ if (!xulBrowserWindow) {
+ return IPC_OK();
+ }
+
+ // ShowTooltip will end up accessing XULElement properties in JS (specifically
+ // BoxObject). However, to get it to JS, we need to make sure we're a
+ // nsFrameLoaderOwner, which implies we're a XULFrameElement. We can then
+ // safely pass Element into JS.
+ RefPtr<nsFrameLoaderOwner> flo = do_QueryObject(mFrameElement);
+ if (!flo) return IPC_OK();
+
+ nsCOMPtr<Element> el = do_QueryInterface(flo);
+ if (!el) return IPC_OK();
+
+ xulBrowserWindow->ShowTooltip(aX, aY, aTooltip, aDirection, el);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvHideTooltip() {
+ nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow = GetXULBrowserWindow();
+ if (!xulBrowserWindow) {
+ return IPC_OK();
+ }
+
+ xulBrowserWindow->HideTooltip();
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMEFocus(
+ const ContentCache& aContentCache, const IMENotification& aIMENotification,
+ NotifyIMEFocusResolver&& aResolve) {
+ if (mIsDestroyed) {
+ return IPC_OK();
+ }
+
+ nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
+ if (!widget) {
+ aResolve(IMENotificationRequests());
+ return IPC_OK();
+ }
+
+ mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
+ IMEStateManager::NotifyIME(aIMENotification, widget, this);
+
+ IMENotificationRequests requests;
+ if (aIMENotification.mMessage == NOTIFY_IME_OF_FOCUS) {
+ requests = widget->IMENotificationRequestsRef();
+ }
+ aResolve(requests);
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMETextChange(
+ const ContentCache& aContentCache,
+ const IMENotification& aIMENotification) {
+ nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
+ if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
+ return IPC_OK();
+ }
+ mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
+ mContentCache.MaybeNotifyIME(widget, aIMENotification);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMECompositionUpdate(
+ const ContentCache& aContentCache,
+ const IMENotification& aIMENotification) {
+ nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
+ if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
+ return IPC_OK();
+ }
+ mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
+ mContentCache.MaybeNotifyIME(widget, aIMENotification);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMESelection(
+ const ContentCache& aContentCache,
+ const IMENotification& aIMENotification) {
+ nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
+ if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
+ return IPC_OK();
+ }
+ mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
+ mContentCache.MaybeNotifyIME(widget, aIMENotification);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvUpdateContentCache(
+ const ContentCache& aContentCache) {
+ nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
+ if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
+ return IPC_OK();
+ }
+
+ mContentCache.AssignContent(aContentCache, widget);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMEMouseButtonEvent(
+ const IMENotification& aIMENotification, bool* aConsumedByIME) {
+ nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
+ if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
+ *aConsumedByIME = false;
+ return IPC_OK();
+ }
+ nsresult rv = IMEStateManager::NotifyIME(aIMENotification, widget, this);
+ *aConsumedByIME = rv == NS_SUCCESS_EVENT_CONSUMED;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvNotifyIMEPositionChange(
+ const ContentCache& aContentCache,
+ const IMENotification& aIMENotification) {
+ nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
+ if (!widget || !IMEStateManager::DoesBrowserParentHaveIMEFocus(this)) {
+ return IPC_OK();
+ }
+ mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
+ mContentCache.MaybeNotifyIME(widget, aIMENotification);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvOnEventNeedingAckHandled(
+ const EventMessage& aMessage) {
+ // This is called when the child process receives WidgetCompositionEvent or
+ // WidgetSelectionEvent.
+ // FYI: Don't check if widget is nullptr here because it's more important to
+ // notify mContentCahce of this than handling something in it.
+ nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
+
+ // While calling OnEventNeedingAckHandled(), BrowserParent *might* be
+ // destroyed since it may send notifications to IME.
+ RefPtr<BrowserParent> kungFuDeathGrip(this);
+ mContentCache.OnEventNeedingAckHandled(widget, aMessage);
+ return IPC_OK();
+}
+
+void BrowserParent::HandledWindowedPluginKeyEvent(
+ const NativeEventData& aKeyEventData, bool aIsConsumed) {
+ DebugOnly<bool> ok =
+ SendHandledWindowedPluginKeyEvent(aKeyEventData, aIsConsumed);
+ NS_WARNING_ASSERTION(ok, "SendHandledWindowedPluginKeyEvent failed");
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvOnWindowedPluginKeyEvent(
+ const NativeEventData& aKeyEventData) {
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (NS_WARN_IF(!widget)) {
+ // Notifies the plugin process of the key event being not consumed by us.
+ HandledWindowedPluginKeyEvent(aKeyEventData, false);
+ return IPC_OK();
+ }
+ nsresult rv = widget->OnWindowedPluginKeyEvent(aKeyEventData, this);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ // Notifies the plugin process of the key event being not consumed by us.
+ HandledWindowedPluginKeyEvent(aKeyEventData, false);
+ return IPC_OK();
+ }
+
+ // If the key event is posted to another process, we need to wait a call
+ // of HandledWindowedPluginKeyEvent(). So, nothing to do here in this case.
+ if (rv == NS_SUCCESS_EVENT_HANDLED_ASYNCHRONOUSLY) {
+ return IPC_OK();
+ }
+
+ // Otherwise, the key event is handled synchronously. Let's notify the
+ // plugin process of the key event's result.
+ bool consumed = (rv == NS_SUCCESS_EVENT_CONSUMED);
+ HandledWindowedPluginKeyEvent(aKeyEventData, consumed);
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvRequestFocus(
+ const bool& aCanRaise, const CallerType aCallerType) {
+ LOGBROWSERFOCUS(("RecvRequestFocus %p, aCanRaise: %d", this, aCanRaise));
+ if (BrowserBridgeParent* bridgeParent = GetBrowserBridgeParent()) {
+ mozilla::Unused << bridgeParent->SendRequestFocus(aCanRaise, aCallerType);
+ return IPC_OK();
+ }
+
+ if (!mFrameElement) {
+ return IPC_OK();
+ }
+
+ nsContentUtils::RequestFrameFocus(*mFrameElement, aCanRaise, aCallerType);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvWheelZoomChange(bool aIncrease) {
+ RefPtr<BrowsingContext> bc = GetBrowsingContext();
+ if (!bc) {
+ return IPC_OK();
+ }
+
+ bc->Canonical()->DispatchWheelZoomChange(aIncrease);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvEnableDisableCommands(
+ const MaybeDiscarded<BrowsingContext>& aContext, const nsString& aAction,
+ nsTArray<nsCString>&& aEnabledCommands,
+ nsTArray<nsCString>&& aDisabledCommands) {
+ if (aContext.IsNullOrDiscarded()) {
+ return IPC_OK();
+ }
+
+ nsCOMPtr<nsIBrowserController> browserController = do_QueryActor(
+ "Controllers", aContext.get_canonical()->GetCurrentWindowGlobal());
+ if (browserController) {
+ browserController->EnableDisableCommands(aAction, aEnabledCommands,
+ aDisabledCommands);
+ }
+
+ return IPC_OK();
+}
+
+LayoutDeviceIntPoint BrowserParent::TransformPoint(
+ const LayoutDeviceIntPoint& aPoint,
+ const LayoutDeviceToLayoutDeviceMatrix4x4& aMatrix) {
+ LayoutDevicePoint floatPoint(aPoint);
+ LayoutDevicePoint floatTransformed = TransformPoint(floatPoint, aMatrix);
+ // The next line loses precision if an out-of-process iframe
+ // has been scaled or rotated.
+ return RoundedToInt(floatTransformed);
+}
+
+LayoutDevicePoint BrowserParent::TransformPoint(
+ const LayoutDevicePoint& aPoint,
+ const LayoutDeviceToLayoutDeviceMatrix4x4& aMatrix) {
+ return aMatrix.TransformPoint(aPoint);
+}
+
+LayoutDeviceIntPoint BrowserParent::TransformParentToChild(
+ const LayoutDeviceIntPoint& aPoint) {
+ LayoutDeviceToLayoutDeviceMatrix4x4 matrix =
+ GetChildToParentConversionMatrix();
+ if (!matrix.Invert()) {
+ return LayoutDeviceIntPoint(0, 0);
+ }
+ return TransformPoint(aPoint, matrix);
+}
+
+LayoutDevicePoint BrowserParent::TransformParentToChild(
+ const LayoutDevicePoint& aPoint) {
+ LayoutDeviceToLayoutDeviceMatrix4x4 matrix =
+ GetChildToParentConversionMatrix();
+ if (!matrix.Invert()) {
+ return LayoutDevicePoint(0.0, 0.0);
+ }
+ return TransformPoint(aPoint, matrix);
+}
+
+LayoutDeviceIntPoint BrowserParent::TransformChildToParent(
+ const LayoutDeviceIntPoint& aPoint) {
+ return TransformPoint(aPoint, GetChildToParentConversionMatrix());
+}
+
+LayoutDevicePoint BrowserParent::TransformChildToParent(
+ const LayoutDevicePoint& aPoint) {
+ return TransformPoint(aPoint, GetChildToParentConversionMatrix());
+}
+
+LayoutDeviceIntRect BrowserParent::TransformChildToParent(
+ const LayoutDeviceIntRect& aRect) {
+ LayoutDeviceToLayoutDeviceMatrix4x4 matrix =
+ GetChildToParentConversionMatrix();
+ LayoutDeviceRect floatRect(aRect);
+ // The outcome is not ideal if an out-of-process iframe has been rotated
+ LayoutDeviceRect floatTransformed = matrix.TransformBounds(floatRect);
+ // The next line loses precision if an out-of-process iframe
+ // has been scaled or rotated.
+ return RoundedToInt(floatTransformed);
+}
+
+LayoutDeviceToLayoutDeviceMatrix4x4
+BrowserParent::GetChildToParentConversionMatrix() {
+ if (mChildToParentConversionMatrix) {
+ return *mChildToParentConversionMatrix;
+ }
+ LayoutDevicePoint offset(-GetChildProcessOffset());
+ return LayoutDeviceToLayoutDeviceMatrix4x4::Translation(offset);
+}
+
+void BrowserParent::SetChildToParentConversionMatrix(
+ const Maybe<LayoutDeviceToLayoutDeviceMatrix4x4>& aMatrix,
+ const ScreenRect& aRemoteDocumentRect) {
+ mChildToParentConversionMatrix = aMatrix;
+ if (mIsDestroyed) {
+ return;
+ }
+ mozilla::Unused << SendChildToParentMatrix(ToUnknownMatrix(aMatrix),
+ aRemoteDocumentRect);
+}
+
+LayoutDeviceIntPoint BrowserParent::GetChildProcessOffset() {
+ // The "toplevel widget" in child processes is always at position
+ // 0,0. Map the event coordinates to match that.
+
+ LayoutDeviceIntPoint offset(0, 0);
+ RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
+ if (!frameLoader) {
+ return offset;
+ }
+ nsIFrame* targetFrame = frameLoader->GetPrimaryFrameOfOwningContent();
+ if (!targetFrame) {
+ return offset;
+ }
+
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (!widget) {
+ return offset;
+ }
+
+ nsPresContext* presContext = targetFrame->PresContext();
+ nsIFrame* rootFrame = presContext->PresShell()->GetRootFrame();
+ nsView* rootView = rootFrame ? rootFrame->GetView() : nullptr;
+ if (!rootView) {
+ return offset;
+ }
+
+ // Note that we don't want to take into account transforms here:
+#if 0
+ nsPoint pt(0, 0);
+ nsLayoutUtils::TransformPoint(targetFrame, rootFrame, pt);
+#endif
+ // In practice, when transforms are applied to this frameLoader, we currently
+ // get the wrong results whether we take transforms into account here or not.
+ // But applying transforms here gives us the wrong results in all
+ // circumstances when transforms are applied, unless they're purely
+ // translational. It also gives us the wrong results whenever CSS transitions
+ // are used to apply transforms, since the offeets aren't updated as the
+ // transition is animated.
+ //
+ // What we actually need to do is apply the transforms to the coordinates of
+ // any events we send to the child, and reverse them for any screen
+ // coordinates that we retrieve from the child.
+
+ // TODO: Once we take into account transforms here, set viewportType
+ // correctly. For now we use Visual as this means we don't apply
+ // the layout-to-visual transform in TranslateViewToWidget().
+ ViewportType viewportType = ViewportType::Visual;
+
+ nsPoint pt = targetFrame->GetOffsetTo(rootFrame);
+ return -nsLayoutUtils::TranslateViewToWidget(presContext, rootView, pt,
+ viewportType, widget);
+}
+
+LayoutDeviceIntPoint BrowserParent::GetClientOffset() {
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ nsCOMPtr<nsIWidget> docWidget = GetDocWidget();
+
+ if (widget == docWidget) {
+ return widget->GetClientOffset();
+ }
+
+ return (docWidget->GetClientOffset() +
+ nsLayoutUtils::WidgetToWidgetOffset(widget, docWidget));
+}
+
+void BrowserParent::StopIMEStateManagement() {
+ if (mIsDestroyed) {
+ return;
+ }
+ Unused << SendStopIMEStateManagement();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvReplyKeyEvent(
+ const WidgetKeyboardEvent& aEvent) {
+ NS_ENSURE_TRUE(mFrameElement, IPC_OK());
+
+ WidgetKeyboardEvent localEvent(aEvent);
+ localEvent.MarkAsHandledInRemoteProcess();
+
+ // Here we convert the WidgetEvent that we received to an Event
+ // to be able to dispatch it to the <browser> element as the target element.
+ Document* doc = mFrameElement->OwnerDoc();
+ nsPresContext* presContext = doc->GetPresContext();
+ NS_ENSURE_TRUE(presContext, IPC_OK());
+
+ AutoHandlingUserInputStatePusher userInpStatePusher(localEvent.IsTrusted(),
+ &localEvent);
+
+ nsEventStatus status = nsEventStatus_eIgnore;
+
+ // Handle access key in this process before dispatching reply event because
+ // ESM handles it before dispatching the event to the DOM tree.
+ if (localEvent.mMessage == eKeyPress &&
+ (localEvent.ModifiersMatchWithAccessKey(AccessKeyType::eChrome) ||
+ localEvent.ModifiersMatchWithAccessKey(AccessKeyType::eContent))) {
+ RefPtr<EventStateManager> esm = presContext->EventStateManager();
+ AutoTArray<uint32_t, 10> accessCharCodes;
+ localEvent.GetAccessKeyCandidates(accessCharCodes);
+ if (esm->HandleAccessKey(&localEvent, presContext, accessCharCodes)) {
+ status = nsEventStatus_eConsumeNoDefault;
+ }
+ }
+
+ EventDispatcher::Dispatch(mFrameElement, presContext, &localEvent, nullptr,
+ &status);
+
+ if (!localEvent.DefaultPrevented() &&
+ !localEvent.mFlags.mIsSynthesizedForTests) {
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (widget) {
+ widget->PostHandleKeyEvent(&localEvent);
+ localEvent.StopPropagation();
+ }
+ }
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvAccessKeyNotHandled(
+ const WidgetKeyboardEvent& aEvent) {
+ NS_ENSURE_TRUE(mFrameElement, IPC_OK());
+
+ // This is called only when this process had focus and HandleAccessKey
+ // message was posted to all remote process and each remote process didn't
+ // execute any content access keys.
+ // XXX If there were two or more remote processes, this may be called
+ // twice or more for a keyboard event, that must be a bug. But how to
+ // detect if received event has already been handled?
+
+ MOZ_ASSERT(aEvent.mMessage == eKeyPress);
+ WidgetKeyboardEvent localEvent(aEvent);
+ localEvent.MarkAsHandledInRemoteProcess();
+ localEvent.mMessage = eAccessKeyNotFound;
+
+ // Here we convert the WidgetEvent that we received to an Event
+ // to be able to dispatch it to the <browser> element as the target element.
+ Document* doc = mFrameElement->OwnerDoc();
+ PresShell* presShell = doc->GetPresShell();
+ NS_ENSURE_TRUE(presShell, IPC_OK());
+
+ if (presShell->CanDispatchEvent()) {
+ nsPresContext* presContext = presShell->GetPresContext();
+ NS_ENSURE_TRUE(presContext, IPC_OK());
+
+ EventDispatcher::Dispatch(mFrameElement, presContext, &localEvent);
+ }
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvRegisterProtocolHandler(
+ const nsString& aScheme, nsIURI* aHandlerURI, const nsString& aTitle,
+ nsIURI* aDocURI) {
+ nsCOMPtr<nsIWebProtocolHandlerRegistrar> registrar =
+ do_GetService(NS_WEBPROTOCOLHANDLERREGISTRAR_CONTRACTID);
+ if (registrar) {
+ registrar->RegisterProtocolHandler(aScheme, aHandlerURI, aTitle, aDocURI,
+ mFrameElement);
+ }
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvOnStateChange(
+ const Maybe<WebProgressData>& aWebProgressData,
+ const RequestData& aRequestData, const uint32_t aStateFlags,
+ const nsresult aStatus,
+ const Maybe<WebProgressStateChangeData>& aStateChangeData) {
+ if (mSuspendedProgressEvents) {
+ return IPC_OK();
+ }
+
+ nsCOMPtr<nsIBrowser> browser = GetBrowser();
+ if (!GetBrowsingContext()->GetWebProgress() || !browser) {
+ return IPC_OK();
+ }
+
+ nsCOMPtr<nsIWebProgress> webProgress;
+ nsCOMPtr<nsIRequest> request;
+ ReconstructWebProgressAndRequest(aWebProgressData, aRequestData,
+ getter_AddRefs(webProgress),
+ getter_AddRefs(request));
+
+ if (aWebProgressData && aWebProgressData->isTopLevel() &&
+ aStateChangeData.isSome()) {
+ Unused << browser->SetIsNavigating(aStateChangeData->isNavigating());
+ Unused << browser->SetMayEnableCharacterEncodingMenu(
+ aStateChangeData->mayEnableCharacterEncodingMenu());
+ Unused << browser->SetCharsetAutodetected(
+ aStateChangeData->charsetAutodetected());
+ Unused << browser->UpdateForStateChange(aStateChangeData->charset(),
+ aStateChangeData->documentURI(),
+ aStateChangeData->contentType());
+ } else if (aStateChangeData.isSome()) {
+ return IPC_FAIL(
+ this,
+ "Unexpected WebProgressStateChangeData for non-top-level WebProgress");
+ }
+
+ GetBrowsingContext()->Top()->GetWebProgress()->OnStateChange(
+ webProgress, request, aStateFlags, aStatus);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvOnProgressChange(
+ const Maybe<WebProgressData>& aWebProgressData,
+ const RequestData& aRequestData, const int32_t aCurSelfProgress,
+ const int32_t aMaxSelfProgress, const int32_t aCurTotalProgress,
+ const int32_t aMaxTotalProgress) {
+ if (mSuspendedProgressEvents) {
+ return IPC_OK();
+ }
+
+ if (!GetBrowsingContext()->GetWebProgress()) {
+ return IPC_OK();
+ }
+
+ nsCOMPtr<nsIWebProgress> webProgress;
+ nsCOMPtr<nsIRequest> request;
+ ReconstructWebProgressAndRequest(aWebProgressData, aRequestData,
+ getter_AddRefs(webProgress),
+ getter_AddRefs(request));
+
+ GetBrowsingContext()->Top()->GetWebProgress()->OnProgressChange(
+ webProgress, request, aCurSelfProgress, aMaxSelfProgress,
+ aCurTotalProgress, aMaxTotalProgress);
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvOnLocationChange(
+ const Maybe<WebProgressData>& aWebProgressData,
+ const RequestData& aRequestData, nsIURI* aLocation, const uint32_t aFlags,
+ const bool aCanGoBack, const bool aCanGoForward,
+ const Maybe<WebProgressLocationChangeData>& aLocationChangeData) {
+ if (mSuspendedProgressEvents) {
+ return IPC_OK();
+ }
+
+ nsCOMPtr<nsIBrowser> browser = GetBrowser();
+ if (!GetBrowsingContext()->GetWebProgress() || !browser) {
+ return IPC_OK();
+ }
+
+ nsCOMPtr<nsIWebProgress> webProgress;
+ nsCOMPtr<nsIRequest> request;
+ ReconstructWebProgressAndRequest(aWebProgressData, aRequestData,
+ getter_AddRefs(webProgress),
+ getter_AddRefs(request));
+
+ Unused << browser->UpdateWebNavigationForLocationChange(aCanGoBack,
+ aCanGoForward);
+
+ if (aWebProgressData && aWebProgressData->isTopLevel() &&
+ aLocationChangeData.isSome()) {
+ Unused << browser->SetIsNavigating(aLocationChangeData->isNavigating());
+ Unused << browser->UpdateForLocationChange(
+ aLocation, aLocationChangeData->charset(),
+ aLocationChangeData->mayEnableCharacterEncodingMenu(),
+ aLocationChangeData->charsetAutodetected(),
+ aLocationChangeData->documentURI(), aLocationChangeData->title(),
+ aLocationChangeData->contentPrincipal(),
+ aLocationChangeData->contentPartitionedPrincipal(),
+ aLocationChangeData->csp(), aLocationChangeData->referrerInfo(),
+ aLocationChangeData->isSyntheticDocument(),
+ aLocationChangeData->requestContextID().isSome(),
+ aLocationChangeData->requestContextID().valueOr(0),
+ aLocationChangeData->contentType());
+ }
+
+ GetBrowsingContext()->Top()->GetWebProgress()->OnLocationChange(
+ webProgress, request, aLocation, aFlags);
+
+ // Since we've now changed Documents, notify the BrowsingContext that we've
+ // changed. Ideally we'd just let the BrowsingContext do this when it changes
+ // the current window global, but that happens before this and we have a lot
+ // of tests that depend on the specific ordering of messages.
+ if (!(aFlags & nsIWebProgressListener::LOCATION_CHANGE_SAME_DOCUMENT)) {
+ GetBrowsingContext()->UpdateSecurityState();
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvOnStatusChange(
+ const Maybe<WebProgressData>& aWebProgressData,
+ const RequestData& aRequestData, const nsresult aStatus,
+ const nsString& aMessage) {
+ if (mSuspendedProgressEvents) {
+ return IPC_OK();
+ }
+
+ if (!GetBrowsingContext()->GetWebProgress()) {
+ return IPC_OK();
+ }
+
+ nsCOMPtr<nsIWebProgress> webProgress;
+ nsCOMPtr<nsIRequest> request;
+ ReconstructWebProgressAndRequest(aWebProgressData, aRequestData,
+ getter_AddRefs(webProgress),
+ getter_AddRefs(request));
+
+ GetBrowsingContext()->Top()->GetWebProgress()->OnStatusChange(
+ webProgress, request, aStatus, aMessage.get());
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvNavigationFinished() {
+ nsCOMPtr<nsIBrowser> browser =
+ mFrameElement ? mFrameElement->AsBrowser() : nullptr;
+
+ if (browser) {
+ browser->SetIsNavigating(false);
+ }
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvNotifyContentBlockingEvent(
+ const uint32_t& aEvent, const RequestData& aRequestData,
+ const bool aBlocked, const nsACString& aTrackingOrigin,
+ nsTArray<nsCString>&& aTrackingFullHashes,
+ const Maybe<
+ mozilla::ContentBlockingNotifier::StorageAccessPermissionGrantedReason>&
+ aReason) {
+ RefPtr<BrowsingContext> bc = GetBrowsingContext();
+
+ if (!bc || bc->IsDiscarded()) {
+ return IPC_OK();
+ }
+
+ // Get the top-level browsing context.
+ bc = bc->Top();
+ RefPtr<dom::WindowGlobalParent> wgp =
+ bc->Canonical()->GetCurrentWindowGlobal();
+
+ // The WindowGlobalParent would be null while running the test
+ // browser_339445.js. This is unexpected and we will address this in a
+ // following bug. For now, we first workaround this issue.
+ if (!wgp) {
+ return IPC_OK();
+ }
+
+ nsCOMPtr<nsIRequest> request = MakeAndAddRef<RemoteWebProgressRequest>(
+ aRequestData.requestURI(), aRequestData.originalRequestURI(),
+ aRequestData.matchedList());
+
+ wgp->NotifyContentBlockingEvent(aEvent, request, aBlocked, aTrackingOrigin,
+ aTrackingFullHashes, aReason);
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSetAllowDeprecatedTls(bool value) {
+ Preferences::SetBool("security.tls.version.enable-deprecated", value);
+ return IPC_OK();
+}
+
+already_AddRefed<nsIBrowser> BrowserParent::GetBrowser() {
+ nsCOMPtr<nsIBrowser> browser;
+ RefPtr<Element> currentElement = mFrameElement;
+
+ // In Responsive Design Mode, mFrameElement will be the <iframe mozbrowser>,
+ // but we want the <xul:browser> that it is embedded in.
+ while (currentElement) {
+ browser = currentElement->AsBrowser();
+ if (browser) {
+ break;
+ }
+
+ BrowsingContext* browsingContext =
+ currentElement->OwnerDoc()->GetBrowsingContext();
+ currentElement =
+ browsingContext ? browsingContext->GetEmbedderElement() : nullptr;
+ }
+
+ return browser.forget();
+}
+
+void BrowserParent::ReconstructWebProgressAndRequest(
+ const Maybe<WebProgressData>& aWebProgressData,
+ const RequestData& aRequestData, nsIWebProgress** aOutWebProgress,
+ nsIRequest** aOutRequest) {
+ MOZ_DIAGNOSTIC_ASSERT(aOutWebProgress,
+ "aOutWebProgress should never be null");
+ MOZ_DIAGNOSTIC_ASSERT(aOutRequest, "aOutRequest should never be null");
+
+ nsCOMPtr<nsIWebProgress> webProgress;
+ if (aWebProgressData) {
+ webProgress = new RemoteWebProgress(aWebProgressData->loadType(),
+ aWebProgressData->isLoadingDocument(),
+ aWebProgressData->isTopLevel());
+ } else {
+ webProgress = new RemoteWebProgress(0, false, false);
+ }
+ webProgress.forget(aOutWebProgress);
+
+ if (aRequestData.requestURI()) {
+ nsCOMPtr<nsIRequest> request = MakeAndAddRef<RemoteWebProgressRequest>(
+ aRequestData.requestURI(), aRequestData.originalRequestURI(),
+ aRequestData.matchedList());
+ request.forget(aOutRequest);
+ } else {
+ *aOutRequest = nullptr;
+ }
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSessionStoreUpdate(
+ const Maybe<nsCString>& aDocShellCaps, const Maybe<bool>& aPrivatedMode,
+ nsTArray<nsCString>&& aPositions, nsTArray<int32_t>&& aPositionDescendants,
+ const nsTArray<InputFormData>& aInputs,
+ const nsTArray<CollectedInputDataValue>& aIdVals,
+ const nsTArray<CollectedInputDataValue>& aXPathVals,
+ nsTArray<nsCString>&& aOrigins, nsTArray<nsString>&& aKeys,
+ nsTArray<nsString>&& aValues, const bool aIsFullStorage,
+ const bool aNeedCollectSHistory, const uint32_t& aFlushId,
+ const bool& aIsFinal, const uint32_t& aEpoch) {
+ UpdateSessionStoreData data;
+ if (aDocShellCaps.isSome()) {
+ data.mDocShellCaps.Construct() = aDocShellCaps.value();
+ }
+ if (aPrivatedMode.isSome()) {
+ data.mIsPrivate.Construct() = aPrivatedMode.value();
+ }
+ if (aPositions.Length() != 0) {
+ data.mPositions.Construct(std::move(aPositions));
+ data.mPositionDescendants.Construct(std::move(aPositionDescendants));
+ }
+ if (aIdVals.Length() != 0) {
+ SessionStoreUtils::ComposeInputData(aIdVals, data.mId.Construct());
+ }
+ if (aXPathVals.Length() != 0) {
+ SessionStoreUtils::ComposeInputData(aXPathVals, data.mXpath.Construct());
+ }
+ if (aInputs.Length() != 0) {
+ nsTArray<int> descendants, numId, numXPath;
+ nsTArray<nsString> innerHTML;
+ nsTArray<nsCString> url;
+ for (const InputFormData& input : aInputs) {
+ descendants.AppendElement(input.descendants);
+ numId.AppendElement(input.numId);
+ numXPath.AppendElement(input.numXPath);
+ innerHTML.AppendElement(input.innerHTML);
+ url.AppendElement(input.url);
+ }
+
+ data.mInputDescendants.Construct(std::move(descendants));
+ data.mNumId.Construct(std::move(numId));
+ data.mNumXPath.Construct(std::move(numXPath));
+ data.mInnerHTML.Construct(std::move(innerHTML));
+ data.mUrl.Construct(std::move(url));
+ }
+ // In normal case, we only update the storage when needed.
+ // However, we need to reset the session storage(aOrigins.Length() will be 0)
+ // if the usage is over the "browser_sessionstore_dom_storage_limit".
+ // In this case, aIsFullStorage is true.
+ if (aOrigins.Length() != 0 || aIsFullStorage) {
+ data.mStorageOrigins.Construct(std::move(aOrigins));
+ data.mStorageKeys.Construct(std::move(aKeys));
+ data.mStorageValues.Construct(std::move(aValues));
+ data.mIsFullStorage.Construct() = aIsFullStorage;
+ }
+
+ nsCOMPtr<nsISessionStoreFunctions> funcs =
+ do_ImportModule("resource://gre/modules/SessionStoreFunctions.jsm");
+ NS_ENSURE_TRUE(funcs, IPC_OK());
+ nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(funcs);
+ AutoJSAPI jsapi;
+ MOZ_ALWAYS_TRUE(jsapi.Init(wrapped->GetJSObjectGlobal()));
+ JS::Rooted<JS::Value> dataVal(jsapi.cx());
+ bool ok = ToJSValue(jsapi.cx(), data, &dataVal);
+ NS_ENSURE_TRUE(ok, IPC_OK());
+
+ nsresult rv = funcs->UpdateSessionStore(mFrameElement, mBrowsingContext,
+ aFlushId, aIsFinal, aEpoch, dataVal,
+ aNeedCollectSHistory);
+ NS_ENSURE_SUCCESS(rv, IPC_OK());
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvIntrinsicSizeOrRatioChanged(
+ const Maybe<IntrinsicSize>& aIntrinsicSize,
+ const Maybe<AspectRatio>& aIntrinsicRatio) {
+ BrowserBridgeParent* bridge = GetBrowserBridgeParent();
+ if (!bridge || !bridge->CanSend()) {
+ return IPC_OK();
+ }
+
+ Unused << bridge->SendIntrinsicSizeOrRatioChanged(aIntrinsicSize,
+ aIntrinsicRatio);
+
+ return IPC_OK();
+}
+
+bool BrowserParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent) {
+ nsCOMPtr<nsIWidget> textInputHandlingWidget = GetTextInputHandlingWidget();
+ if (!textInputHandlingWidget) {
+ return true;
+ }
+ if (NS_WARN_IF(!mContentCache.HandleQueryContentEvent(
+ aEvent, textInputHandlingWidget)) ||
+ NS_WARN_IF(aEvent.Failed())) {
+ return true;
+ }
+ switch (aEvent.mMessage) {
+ case eQueryTextRect:
+ case eQueryCaretRect:
+ case eQueryEditorRect: {
+ nsCOMPtr<nsIWidget> browserWidget = GetWidget();
+ if (browserWidget != textInputHandlingWidget) {
+ aEvent.mReply->mRect += nsLayoutUtils::WidgetToWidgetOffset(
+ browserWidget, textInputHandlingWidget);
+ }
+ aEvent.mReply->mRect = TransformChildToParent(aEvent.mReply->mRect);
+ break;
+ }
+ default:
+ break;
+ }
+ return true;
+}
+
+bool BrowserParent::SendCompositionEvent(WidgetCompositionEvent& aEvent) {
+ if (mIsDestroyed) {
+ return false;
+ }
+
+ if (!mContentCache.OnCompositionEvent(aEvent)) {
+ return true;
+ }
+
+ bool ret = Manager()->IsInputPriorityEventEnabled()
+ ? PBrowserParent::SendCompositionEvent(aEvent)
+ : PBrowserParent::SendNormalPriorityCompositionEvent(aEvent);
+ if (NS_WARN_IF(!ret)) {
+ return false;
+ }
+ MOZ_ASSERT(aEvent.HasBeenPostedToRemoteProcess());
+ return true;
+}
+
+bool BrowserParent::SendSelectionEvent(WidgetSelectionEvent& aEvent) {
+ if (mIsDestroyed) {
+ return false;
+ }
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (!widget) {
+ return true;
+ }
+ mContentCache.OnSelectionEvent(aEvent);
+ bool ret = Manager()->IsInputPriorityEventEnabled()
+ ? PBrowserParent::SendSelectionEvent(aEvent)
+ : PBrowserParent::SendNormalPrioritySelectionEvent(aEvent);
+ if (NS_WARN_IF(!ret)) {
+ return false;
+ }
+ MOZ_ASSERT(aEvent.HasBeenPostedToRemoteProcess());
+ aEvent.mSucceeded = true;
+ return true;
+}
+
+bool BrowserParent::SendPasteTransferable(
+ const IPCDataTransfer& aDataTransfer, const bool& aIsPrivateData,
+ nsIPrincipal* aRequestingPrincipal,
+ const nsContentPolicyType& aContentPolicyType) {
+ return PBrowserParent::SendPasteTransferable(
+ aDataTransfer, aIsPrivateData, aRequestingPrincipal, aContentPolicyType);
+}
+
+/* static */
+void BrowserParent::SetTopLevelWebFocus(BrowserParent* aBrowserParent) {
+ BrowserParent* old = GetFocused();
+ if (aBrowserParent && !aBrowserParent->GetBrowserBridgeParent()) {
+ // top-level Web content
+ sTopLevelWebFocus = aBrowserParent;
+ BrowserParent* bp = UpdateFocus();
+ if (old != bp) {
+ LOGBROWSERFOCUS(
+ ("SetTopLevelWebFocus updated focus; old: %p, new: %p", old, bp));
+ IMEStateManager::OnFocusMovedBetweenBrowsers(old, bp);
+ }
+ }
+}
+
+/* static */
+void BrowserParent::UnsetTopLevelWebFocus(BrowserParent* aBrowserParent) {
+ BrowserParent* old = GetFocused();
+ if (sTopLevelWebFocus == aBrowserParent) {
+ // top-level Web content
+ sTopLevelWebFocus = nullptr;
+ sFocus = nullptr;
+ if (old) {
+ LOGBROWSERFOCUS(
+ ("UnsetTopLevelWebFocus moved focus to chrome; old: %p", old));
+ IMEStateManager::OnFocusMovedBetweenBrowsers(old, nullptr);
+ }
+ }
+}
+
+/* static */
+void BrowserParent::UpdateFocusFromBrowsingContext() {
+ BrowserParent* old = GetFocused();
+ BrowserParent* bp = UpdateFocus();
+ if (old != bp) {
+ LOGBROWSERFOCUS(
+ ("UpdateFocusFromBrowsingContext updated focus; old: %p, new: %p", old,
+ bp));
+ IMEStateManager::OnFocusMovedBetweenBrowsers(old, bp);
+ }
+}
+
+/* static */
+BrowserParent* BrowserParent::UpdateFocus() {
+ if (!sTopLevelWebFocus) {
+ sFocus = nullptr;
+ return nullptr;
+ }
+ nsFocusManager* fm = nsFocusManager::GetFocusManager();
+ if (fm) {
+ BrowsingContext* bc = fm->GetFocusedBrowsingContextInChrome();
+ if (bc) {
+ BrowsingContext* top = bc->Top();
+ MOZ_ASSERT(top, "Should always have a top BrowsingContext.");
+ CanonicalBrowsingContext* canonicalTop = top->Canonical();
+ MOZ_ASSERT(canonicalTop,
+ "Casting to canonical should always be possible in the parent "
+ "process (top case).");
+ WindowGlobalParent* globalTop = canonicalTop->GetCurrentWindowGlobal();
+ if (globalTop) {
+ RefPtr<BrowserParent> globalTopParent = globalTop->GetBrowserParent();
+ if (sTopLevelWebFocus == globalTopParent) {
+ CanonicalBrowsingContext* canonical = bc->Canonical();
+ MOZ_ASSERT(
+ canonical,
+ "Casting to canonical should always be possible in the parent "
+ "process.");
+ WindowGlobalParent* global = canonical->GetCurrentWindowGlobal();
+ if (global) {
+ RefPtr<BrowserParent> parent = global->GetBrowserParent();
+ sFocus = parent;
+ return sFocus;
+ }
+ LOGBROWSERFOCUS(
+ ("Focused BrowsingContext did not have WindowGlobalParent."));
+ }
+ } else {
+ LOGBROWSERFOCUS(
+ ("Top-level BrowsingContext did not have WindowGlobalParent."));
+ }
+ }
+ }
+ sFocus = sTopLevelWebFocus;
+ return sFocus;
+}
+
+/* static */
+void BrowserParent::UnsetTopLevelWebFocusAll() {
+ if (sTopLevelWebFocus) {
+ UnsetTopLevelWebFocus(sTopLevelWebFocus);
+ }
+}
+
+/* static */
+void BrowserParent::UnsetLastMouseRemoteTarget(BrowserParent* aBrowserParent) {
+ if (sLastMouseRemoteTarget == aBrowserParent) {
+ sLastMouseRemoteTarget = nullptr;
+ }
+}
+
+/* static */
+void BrowserParent::UnsetPointerLockedRemoteTarget(
+ BrowserParent* aBrowserParent) {
+ if (sPointerLockedRemoteTarget == aBrowserParent) {
+ sPointerLockedRemoteTarget = nullptr;
+ }
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvRequestIMEToCommitComposition(
+ const bool& aCancel, bool* aIsCommitted, nsString* aCommittedString) {
+ nsCOMPtr<nsIWidget> widget = GetTextInputHandlingWidget();
+ if (!widget) {
+ *aIsCommitted = false;
+ return IPC_OK();
+ }
+
+ *aIsCommitted = mContentCache.RequestIMEToCommitComposition(
+ widget, aCancel, *aCommittedString);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvGetInputContext(
+ widget::IMEState* aState) {
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (!widget) {
+ *aState = widget::IMEState(IMEEnabled::Disabled,
+ IMEState::OPEN_STATE_NOT_SUPPORTED);
+ return IPC_OK();
+ }
+
+ *aState = widget->GetInputContext().mIMEState;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSetInputContext(
+ const InputContext& aContext, const InputContextAction& aAction) {
+ IMEStateManager::SetInputContextForChildProcess(this, aContext, aAction);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSetNativeChildOfShareableWindow(
+ const uintptr_t& aChildWindow) {
+#if defined(XP_WIN)
+ nsCOMPtr<nsIWidget> widget = GetTopLevelWidget();
+ if (widget) {
+ // Note that this call will probably cause a sync native message to the
+ // process that owns the child window.
+ widget->SetNativeData(NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW, aChildWindow);
+ }
+ return IPC_OK();
+#else
+ MOZ_ASSERT_UNREACHABLE(
+ "BrowserParent::RecvSetNativeChildOfShareableWindow not implemented!");
+ return IPC_FAIL_NO_REASON(this);
+#endif
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvDispatchFocusToTopLevelWindow() {
+ if (nsCOMPtr<nsIWidget> widget = GetTopLevelWidget()) {
+ widget->SetFocus(nsIWidget::Raise::No, CallerType::System);
+ }
+ return IPC_OK();
+}
+
+bool BrowserParent::ReceiveMessage(const nsString& aMessage, bool aSync,
+ StructuredCloneData* aData,
+ nsTArray<StructuredCloneData>* aRetVal) {
+ // If we're for an oop iframe, don't deliver messages to the wrong place.
+ if (mBrowserBridgeParent) {
+ return true;
+ }
+
+ RefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
+ if (frameLoader && frameLoader->GetFrameMessageManager()) {
+ RefPtr<nsFrameMessageManager> manager =
+ frameLoader->GetFrameMessageManager();
+
+ manager->ReceiveMessage(mFrameElement, frameLoader, aMessage, aSync, aData,
+ aRetVal, IgnoreErrors());
+ }
+ return true;
+}
+
+// nsIAuthPromptProvider
+
+// This method is largely copied from nsDocShell::GetAuthPrompt
+NS_IMETHODIMP
+BrowserParent::GetAuthPrompt(uint32_t aPromptReason, const nsIID& iid,
+ void** aResult) {
+ // we're either allowing auth, or it's a proxy request
+ nsresult rv;
+ nsCOMPtr<nsIPromptFactory> wwatch =
+ do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsPIDOMWindowOuter> window;
+ RefPtr<Element> frame = mFrameElement;
+ if (frame) window = frame->OwnerDoc()->GetWindow();
+
+ // Get an auth prompter for our window so that the parenting
+ // of the dialogs works as it should when using tabs.
+ nsCOMPtr<nsISupports> prompt;
+ rv = wwatch->GetPrompt(window, iid, getter_AddRefs(prompt));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsILoginManagerAuthPrompter> prompter = do_QueryInterface(prompt);
+ if (prompter) {
+ prompter->SetBrowser(mFrameElement);
+ }
+
+ *aResult = prompt.forget().take();
+ return NS_OK;
+}
+
+PColorPickerParent* BrowserParent::AllocPColorPickerParent(
+ const nsString& aTitle, const nsString& aInitialColor) {
+ return new ColorPickerParent(aTitle, aInitialColor);
+}
+
+bool BrowserParent::DeallocPColorPickerParent(PColorPickerParent* actor) {
+ delete actor;
+ return true;
+}
+
+already_AddRefed<nsFrameLoader> BrowserParent::GetFrameLoader(
+ bool aUseCachedFrameLoaderAfterDestroy) const {
+ if (mIsDestroyed && !aUseCachedFrameLoaderAfterDestroy) {
+ return nullptr;
+ }
+
+ if (mFrameLoader) {
+ RefPtr<nsFrameLoader> fl = mFrameLoader;
+ return fl.forget();
+ }
+ RefPtr<Element> frameElement(mFrameElement);
+ RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(frameElement);
+ return frameLoaderOwner ? frameLoaderOwner->GetFrameLoader() : nullptr;
+}
+
+void BrowserParent::TryCacheDPIAndScale() {
+ if (mDPI > 0) {
+ return;
+ }
+
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+
+ if (widget) {
+ mDPI = widget->GetDPI();
+ mRounding = widget->RoundsWidgetCoordinatesTo();
+ mDefaultScale = widget->GetDefaultScale();
+ }
+}
+
+void BrowserParent::ApzAwareEventRoutingToChild(
+ ScrollableLayerGuid* aOutTargetGuid, uint64_t* aOutInputBlockId,
+ nsEventStatus* aOutApzResponse) {
+ // Let the widget know that the event will be sent to the child process,
+ // which will (hopefully) send a confirmation notice back to APZ.
+ // Do this even if APZ is off since we need it for swipe gesture support on
+ // OS X without APZ.
+ InputAPZContext::SetRoutedToChildProcess();
+
+ if (AsyncPanZoomEnabled()) {
+ if (aOutTargetGuid) {
+ *aOutTargetGuid = InputAPZContext::GetTargetLayerGuid();
+
+ // There may be cases where the APZ hit-testing code came to a different
+ // conclusion than the main-thread hit-testing code as to where the event
+ // is destined. In such cases the layersId of the APZ result may not match
+ // the layersId of this RemoteLayerTreeOwner. In such cases the
+ // main-thread hit- testing code "wins" so we need to update the guid to
+ // reflect this.
+ if (mRemoteLayerTreeOwner.IsInitialized()) {
+ if (aOutTargetGuid->mLayersId != mRemoteLayerTreeOwner.GetLayersId()) {
+ *aOutTargetGuid =
+ ScrollableLayerGuid(mRemoteLayerTreeOwner.GetLayersId(), 0,
+ ScrollableLayerGuid::NULL_SCROLL_ID);
+ }
+ }
+ }
+ if (aOutInputBlockId) {
+ *aOutInputBlockId = InputAPZContext::GetInputBlockId();
+ }
+ if (aOutApzResponse) {
+ *aOutApzResponse = InputAPZContext::GetApzResponse();
+
+ // We can get here without there being an InputAPZContext on the stack
+ // if a non-native event synthesization function (such as
+ // nsIDOMWindowUtils.sendTouchEvent()) was used in the parent process to
+ // synthesize an event that's targeting a content process. Such events do
+ // not go through APZ. Without an InputAPZContext on the stack we pick up
+ // the default value "eSentinel" which cannot be sent over IPC, so replace
+ // it with "eIgnore" instead, which what APZ uses when it ignores an
+ // event. If a caller needs the ability to synthesize a event with a
+ // different APZ response, a native event synthesization function (such as
+ // sendNativeTouchPoint()) can be used.
+ if (*aOutApzResponse == nsEventStatus_eSentinel) {
+ *aOutApzResponse = nsEventStatus_eIgnore;
+ }
+ }
+ } else {
+ if (aOutInputBlockId) {
+ *aOutInputBlockId = 0;
+ }
+ if (aOutApzResponse) {
+ *aOutApzResponse = nsEventStatus_eIgnore;
+ }
+ }
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvRespondStartSwipeEvent(
+ const uint64_t& aInputBlockId, const bool& aStartSwipe) {
+ if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
+ widget->ReportSwipeStarted(aInputBlockId, aStartSwipe);
+ }
+ return IPC_OK();
+}
+
+bool BrowserParent::GetDocShellIsActive() {
+ return mBrowsingContext && mBrowsingContext->IsActive();
+}
+
+bool BrowserParent::GetHasPresented() { return mHasPresented; }
+
+bool BrowserParent::GetHasLayers() { return mHasLayers; }
+
+bool BrowserParent::GetRenderLayers() { return mRenderLayers; }
+
+void BrowserParent::SetRenderLayers(bool aEnabled) {
+ if (mActiveInPriorityManager != aEnabled) {
+ mActiveInPriorityManager = aEnabled;
+ // Let's inform the priority manager. This operation can end up with the
+ // changing of the process priority.
+ ProcessPriorityManager::TabActivityChanged(this, aEnabled);
+ }
+
+ if (aEnabled == mRenderLayers) {
+ if (aEnabled && mHasLayers && mPreserveLayers) {
+ // RenderLayers might be called when we've been preserving layers,
+ // and already had layers uploaded. In that case, the MozLayerTreeReady
+ // event will not naturally arrive, which can confuse the front-end
+ // layer. So we fire the event here.
+ RefPtr<BrowserParent> self = this;
+ LayersObserverEpoch epoch = mLayerTreeEpoch;
+ NS_DispatchToMainThread(NS_NewRunnableFunction(
+ "dom::BrowserParent::RenderLayers", [self, epoch]() {
+ MOZ_ASSERT(NS_IsMainThread());
+ self->LayerTreeUpdate(epoch, true);
+ }));
+ }
+
+ return;
+ }
+
+ // Preserve layers means that attempts to stop rendering layers
+ // will be ignored.
+ if (!aEnabled && mPreserveLayers) {
+ return;
+ }
+
+ mRenderLayers = aEnabled;
+
+ SetRenderLayersInternal(aEnabled);
+}
+
+void BrowserParent::SetRenderLayersInternal(bool aEnabled) {
+ // Increment the epoch so that layer tree updates from previous
+ // RenderLayers requests are ignored.
+ mLayerTreeEpoch = mLayerTreeEpoch.Next();
+
+ Unused << SendRenderLayers(aEnabled, mLayerTreeEpoch);
+
+ // Ask the child to repaint using the PHangMonitor channel/thread (which may
+ // be less congested).
+ if (aEnabled) {
+ Manager()->PaintTabWhileInterruptingJS(this, mLayerTreeEpoch);
+ }
+}
+
+void BrowserParent::PreserveLayers(bool aPreserveLayers) {
+ mPreserveLayers = aPreserveLayers;
+}
+
+void BrowserParent::NotifyResolutionChanged() {
+ if (!mIsDestroyed) {
+ // TryCacheDPIAndScale()'s cache is keyed off of
+ // mDPI being greater than 0, so this invalidates it.
+ mDPI = -1;
+ TryCacheDPIAndScale();
+ // If mDPI was set to -1 to invalidate it and then TryCacheDPIAndScale
+ // fails to cache the values, then mDefaultScale.scale might be invalid.
+ // We don't want to send that value to content. Just send -1 for it too in
+ // that case.
+ Unused << SendUIResolutionChanged(mDPI, mRounding,
+ mDPI < 0 ? -1.0 : mDefaultScale.scale);
+ }
+}
+
+void BrowserParent::Deprioritize() {
+ if (mActiveInPriorityManager) {
+ ProcessPriorityManager::TabActivityChanged(this, false);
+ mActiveInPriorityManager = false;
+ }
+}
+
+bool BrowserParent::StartApzAutoscroll(float aAnchorX, float aAnchorY,
+ nsViewID aScrollId,
+ uint32_t aPresShellId) {
+ if (!AsyncPanZoomEnabled()) {
+ return false;
+ }
+
+ bool success = false;
+ if (mRemoteLayerTreeOwner.IsInitialized()) {
+ layers::LayersId layersId = mRemoteLayerTreeOwner.GetLayersId();
+ if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
+ ScrollableLayerGuid guid(layersId, aPresShellId, aScrollId);
+
+ // The anchor coordinates that are passed in are relative to the origin
+ // of the screen, but we are sending them to APZ which only knows about
+ // coordinates relative to the widget, so convert them accordingly.
+ CSSPoint anchorCss{aAnchorX, aAnchorY};
+ LayoutDeviceIntPoint anchor =
+ RoundedToInt(anchorCss * widget->GetDefaultScale());
+ anchor -= widget->WidgetToScreenOffset();
+
+ success = widget->StartAsyncAutoscroll(
+ ViewAs<ScreenPixel>(
+ anchor, PixelCastJustification::LayoutDeviceIsScreenForBounds),
+ guid);
+ }
+ }
+ return success;
+}
+
+void BrowserParent::StopApzAutoscroll(nsViewID aScrollId,
+ uint32_t aPresShellId) {
+ if (!AsyncPanZoomEnabled()) {
+ return;
+ }
+
+ if (mRemoteLayerTreeOwner.IsInitialized()) {
+ layers::LayersId layersId = mRemoteLayerTreeOwner.GetLayersId();
+ if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
+ ScrollableLayerGuid guid(layersId, aPresShellId, aScrollId);
+
+ widget->StopAsyncAutoscroll(guid);
+ }
+ }
+}
+
+bool BrowserParent::CanCancelContentJS(
+ nsIRemoteTab::NavigationType aNavigationType, int32_t aNavigationIndex,
+ nsIURI* aNavigationURI) const {
+ // Pre-checking if we can cancel content js in the parent is only
+ // supported when session history in the parent is enabled.
+ if (!mozilla::SessionHistoryInParent()) {
+ // If session history in the parent isn't enabled, this check will
+ // be fully done in BrowserChild::CanCancelContentJS
+ return true;
+ }
+
+ nsCOMPtr<nsISHistory> history = mBrowsingContext->GetSessionHistory();
+
+ if (!history) {
+ // If there is no history we can't possibly know if it's ok to
+ // cancel content js.
+ return false;
+ }
+
+ int32_t current;
+ NS_ENSURE_SUCCESS(history->GetIndex(&current), false);
+
+ if (current == -1) {
+ // This tab has no history! Just return.
+ return false;
+ }
+
+ nsCOMPtr<nsISHEntry> entry;
+ NS_ENSURE_SUCCESS(history->GetEntryAtIndex(current, getter_AddRefs(entry)),
+ false);
+
+ nsCOMPtr<nsIURI> currentURI = entry->GetURI();
+ if (!currentURI->SchemeIs("http") && !currentURI->SchemeIs("https") &&
+ !currentURI->SchemeIs("file")) {
+ // Only cancel content JS for http(s) and file URIs. Other URIs are probably
+ // internal and we should just let them run to completion.
+ return false;
+ }
+
+ if (aNavigationType == nsIRemoteTab::NAVIGATE_BACK) {
+ aNavigationIndex = current - 1;
+ } else if (aNavigationType == nsIRemoteTab::NAVIGATE_FORWARD) {
+ aNavigationIndex = current + 1;
+ } else if (aNavigationType == nsIRemoteTab::NAVIGATE_URL) {
+ if (!aNavigationURI) {
+ return false;
+ }
+
+ if (aNavigationURI->SchemeIs("javascript")) {
+ // "javascript:" URIs don't (necessarily) trigger navigation to a
+ // different page, so don't allow the current page's JS to terminate.
+ return false;
+ }
+
+ // If navigating directly to a URL (e.g. via hitting Enter in the location
+ // bar), then we can cancel anytime the next URL is different from the
+ // current, *excluding* the ref ("#").
+ bool equals;
+ NS_ENSURE_SUCCESS(currentURI->EqualsExceptRef(aNavigationURI, &equals),
+ false);
+ return !equals;
+ }
+ // Note: aNavigationType may also be NAVIGATE_INDEX, in which case we don't
+ // need to do anything special.
+
+ int32_t delta = aNavigationIndex > current ? 1 : -1;
+ for (int32_t i = current + delta; i != aNavigationIndex + delta; i += delta) {
+ nsCOMPtr<nsISHEntry> nextEntry;
+ // If `i` happens to be negative, this call will fail (which is what we
+ // would want to happen).
+ NS_ENSURE_SUCCESS(history->GetEntryAtIndex(i, getter_AddRefs(nextEntry)),
+ false);
+
+ nsCOMPtr<nsISHEntry> laterEntry = delta == 1 ? nextEntry : entry;
+ nsCOMPtr<nsIURI> thisURI = entry->GetURI();
+ nsCOMPtr<nsIURI> nextURI = nextEntry->GetURI();
+
+ // If we changed origin and the load wasn't in a subframe, we know it was
+ // a full document load, so we can cancel the content JS safely.
+ if (!laterEntry->GetIsSubFrame()) {
+ nsAutoCString thisHost;
+ NS_ENSURE_SUCCESS(thisURI->GetPrePath(thisHost), false);
+
+ nsAutoCString nextHost;
+ NS_ENSURE_SUCCESS(nextURI->GetPrePath(nextHost), false);
+
+ if (!thisHost.Equals(nextHost)) {
+ return true;
+ }
+ }
+
+ entry = nextEntry;
+ }
+
+ return false;
+}
+
+void BrowserParent::SuppressDisplayport(bool aEnabled) {
+ if (IsDestroyed()) {
+ return;
+ }
+
+#ifdef DEBUG
+ if (aEnabled) {
+ mActiveSupressDisplayportCount++;
+ } else {
+ mActiveSupressDisplayportCount--;
+ }
+ MOZ_ASSERT(mActiveSupressDisplayportCount >= 0);
+#endif
+
+ Unused << SendSuppressDisplayport(aEnabled);
+}
+
+void BrowserParent::NavigateByKey(bool aForward, bool aForDocumentNavigation) {
+ Unused << SendNavigateByKey(aForward, aForDocumentNavigation);
+}
+
+void BrowserParent::LayerTreeUpdate(const LayersObserverEpoch& aEpoch,
+ bool aActive) {
+ // Ignore updates if we're an out-of-process iframe. For oop iframes, our
+ // |mFrameElement| is that of the top-level document, and so AsyncTabSwitcher
+ // will treat MozLayerTreeReady / MozLayerTreeCleared events as if they came
+ // from the top-level tab, which is wrong.
+ //
+ // XXX: Should we still be updating |mHasLayers|?
+ if (GetBrowserBridgeParent()) {
+ return;
+ }
+
+ // Ignore updates from old epochs. They might tell us that layers are
+ // available when we've already sent a message to clear them. We can't trust
+ // the update in that case since layers could disappear anytime after that.
+ if (aEpoch != mLayerTreeEpoch || mIsDestroyed) {
+ return;
+ }
+
+ RefPtr<EventTarget> target = mFrameElement;
+ if (!target) {
+ NS_WARNING("Could not locate target for layer tree message.");
+ return;
+ }
+
+ mHasLayers = aActive;
+
+ RefPtr<Event> event = NS_NewDOMEvent(mFrameElement, nullptr, nullptr);
+ if (aActive) {
+ mHasPresented = true;
+ event->InitEvent(u"MozLayerTreeReady"_ns, true, false);
+ } else {
+ event->InitEvent(u"MozLayerTreeCleared"_ns, true, false);
+ }
+ event->SetTrusted(true);
+ event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
+ mFrameElement->DispatchEvent(*event);
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvPaintWhileInterruptingJSNoOp(
+ const LayersObserverEpoch& aEpoch) {
+ // We sent a PaintWhileInterruptingJS message when layers were already
+ // visible. In this case, we should act as if an update occurred even though
+ // we already have the layers.
+ LayerTreeUpdate(aEpoch, true);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvRemotePaintIsReady() {
+ RefPtr<EventTarget> target = mFrameElement;
+ if (!target) {
+ NS_WARNING("Could not locate target for MozAfterRemotePaint message.");
+ return IPC_OK();
+ }
+
+ RefPtr<Event> event = NS_NewDOMEvent(mFrameElement, nullptr, nullptr);
+ event->InitEvent(u"MozAfterRemotePaint"_ns, false, false);
+ event->SetTrusted(true);
+ event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
+ mFrameElement->DispatchEvent(*event);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvRemoteIsReadyToHandleInputEvents() {
+ // When enabling input event prioritization, input events may preempt other
+ // normal priority IPC messages. To prevent the input events preempt
+ // PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to
+ // notify the parent that BrowserChild is created and ready to handle input
+ // events.
+ SetReadyToHandleInputEvents();
+ return IPC_OK();
+}
+
+mozilla::plugins::PPluginWidgetParent*
+BrowserParent::AllocPPluginWidgetParent() {
+#ifdef XP_WIN
+ return new mozilla::plugins::PluginWidgetParent();
+#else
+ MOZ_ASSERT_UNREACHABLE("AllocPPluginWidgetParent only supports Windows");
+ return nullptr;
+#endif
+}
+
+bool BrowserParent::DeallocPPluginWidgetParent(
+ mozilla::plugins::PPluginWidgetParent* aActor) {
+ delete aActor;
+ return true;
+}
+
+PPaymentRequestParent* BrowserParent::AllocPPaymentRequestParent() {
+ RefPtr<PaymentRequestParent> actor = new PaymentRequestParent();
+ return actor.forget().take();
+}
+
+bool BrowserParent::DeallocPPaymentRequestParent(
+ PPaymentRequestParent* aActor) {
+ RefPtr<PaymentRequestParent> actor =
+ dont_AddRef(static_cast<PaymentRequestParent*>(aActor));
+ return true;
+}
+
+nsresult BrowserParent::HandleEvent(Event* aEvent) {
+ if (mIsDestroyed) {
+ return NS_OK;
+ }
+
+ nsAutoString eventType;
+ aEvent->GetType(eventType);
+ if (eventType.EqualsLiteral("MozUpdateWindowPos") ||
+ eventType.EqualsLiteral("fullscreenchange")) {
+ // Events that signify the window moving are used to update the position
+ // and notify the BrowserChild.
+ return UpdatePosition();
+ }
+ return NS_OK;
+}
+
+class FakeChannel final : public nsIChannel,
+ public nsIAuthPromptCallback,
+ public nsIInterfaceRequestor,
+ public nsILoadContext {
+ public:
+ FakeChannel(const nsCString& aUri, uint64_t aCallbackId, Element* aElement)
+ : mCallbackId(aCallbackId), mElement(aElement) {
+ NS_NewURI(getter_AddRefs(mUri), aUri);
+ }
+
+ NS_DECL_ISUPPORTS
+
+#define NO_IMPL \
+ override { return NS_ERROR_NOT_IMPLEMENTED; }
+ NS_IMETHOD GetName(nsACString&) NO_IMPL;
+ NS_IMETHOD IsPending(bool*) NO_IMPL;
+ NS_IMETHOD GetStatus(nsresult*) NO_IMPL;
+ NS_IMETHOD Cancel(nsresult) NO_IMPL;
+ NS_IMETHOD GetCanceled(bool* aCanceled) NO_IMPL;
+ NS_IMETHOD Suspend() NO_IMPL;
+ NS_IMETHOD Resume() NO_IMPL;
+ NS_IMETHOD GetLoadGroup(nsILoadGroup**) NO_IMPL;
+ NS_IMETHOD SetLoadGroup(nsILoadGroup*) NO_IMPL;
+ NS_IMETHOD SetLoadFlags(nsLoadFlags) NO_IMPL;
+ NS_IMETHOD GetLoadFlags(nsLoadFlags*) NO_IMPL;
+ NS_IMETHOD GetTRRMode(nsIRequest::TRRMode* aTRRMode) NO_IMPL;
+ NS_IMETHOD SetTRRMode(nsIRequest::TRRMode aMode) NO_IMPL;
+ NS_IMETHOD GetIsDocument(bool*) NO_IMPL;
+ NS_IMETHOD GetOriginalURI(nsIURI**) NO_IMPL;
+ NS_IMETHOD SetOriginalURI(nsIURI*) NO_IMPL;
+ NS_IMETHOD GetURI(nsIURI** aUri) override {
+ nsCOMPtr<nsIURI> copy = mUri;
+ copy.forget(aUri);
+ return NS_OK;
+ }
+ NS_IMETHOD GetOwner(nsISupports**) NO_IMPL;
+ NS_IMETHOD SetOwner(nsISupports*) NO_IMPL;
+ NS_IMETHOD GetLoadInfo(nsILoadInfo** aLoadInfo) override {
+ nsCOMPtr<nsILoadInfo> copy = mLoadInfo;
+ copy.forget(aLoadInfo);
+ return NS_OK;
+ }
+ NS_IMETHOD SetLoadInfo(nsILoadInfo* aLoadInfo) override {
+ mLoadInfo = aLoadInfo;
+ return NS_OK;
+ }
+ NS_IMETHOD GetNotificationCallbacks(
+ nsIInterfaceRequestor** aRequestor) override {
+ NS_ADDREF(*aRequestor = this);
+ return NS_OK;
+ }
+ NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor*) NO_IMPL;
+ NS_IMETHOD GetSecurityInfo(nsISupports**) NO_IMPL;
+ NS_IMETHOD GetContentType(nsACString&) NO_IMPL;
+ NS_IMETHOD SetContentType(const nsACString&) NO_IMPL;
+ NS_IMETHOD GetContentCharset(nsACString&) NO_IMPL;
+ NS_IMETHOD SetContentCharset(const nsACString&) NO_IMPL;
+ NS_IMETHOD GetContentLength(int64_t*) NO_IMPL;
+ NS_IMETHOD SetContentLength(int64_t) NO_IMPL;
+ NS_IMETHOD Open(nsIInputStream**) NO_IMPL;
+ NS_IMETHOD AsyncOpen(nsIStreamListener*) NO_IMPL;
+ NS_IMETHOD GetContentDisposition(uint32_t*) NO_IMPL;
+ NS_IMETHOD SetContentDisposition(uint32_t) NO_IMPL;
+ NS_IMETHOD GetContentDispositionFilename(nsAString&) NO_IMPL;
+ NS_IMETHOD SetContentDispositionFilename(const nsAString&) NO_IMPL;
+ NS_IMETHOD GetContentDispositionHeader(nsACString&) NO_IMPL;
+ NS_IMETHOD OnAuthAvailable(nsISupports* aContext,
+ nsIAuthInformation* aAuthInfo) override;
+ NS_IMETHOD OnAuthCancelled(nsISupports* aContext, bool userCancel) override;
+ NS_IMETHOD GetInterface(const nsIID& uuid, void** result) override {
+ return QueryInterface(uuid, result);
+ }
+ NS_IMETHOD GetAssociatedWindow(mozIDOMWindowProxy**) NO_IMPL;
+ NS_IMETHOD GetTopWindow(mozIDOMWindowProxy**) NO_IMPL;
+ NS_IMETHOD GetTopFrameElement(Element** aElement) override {
+ RefPtr<Element> elem = mElement;
+ elem.forget(aElement);
+ return NS_OK;
+ }
+ NS_IMETHOD GetIsContent(bool*) NO_IMPL;
+ NS_IMETHOD GetUsePrivateBrowsing(bool*) NO_IMPL;
+ NS_IMETHOD SetUsePrivateBrowsing(bool) NO_IMPL;
+ NS_IMETHOD SetPrivateBrowsing(bool) NO_IMPL;
+ NS_IMETHOD GetScriptableOriginAttributes(JSContext*,
+ JS::MutableHandleValue) NO_IMPL;
+ NS_IMETHOD_(void)
+ GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override {}
+ NS_IMETHOD GetUseRemoteTabs(bool*) NO_IMPL;
+ NS_IMETHOD SetRemoteTabs(bool) NO_IMPL;
+ NS_IMETHOD GetUseRemoteSubframes(bool*) NO_IMPL;
+ NS_IMETHOD SetRemoteSubframes(bool) NO_IMPL;
+ NS_IMETHOD GetUseTrackingProtection(bool*) NO_IMPL;
+ NS_IMETHOD SetUseTrackingProtection(bool) NO_IMPL;
+#undef NO_IMPL
+
+ protected:
+ ~FakeChannel() = default;
+
+ nsCOMPtr<nsIURI> mUri;
+ uint64_t mCallbackId;
+ RefPtr<Element> mElement;
+ nsCOMPtr<nsILoadInfo> mLoadInfo;
+};
+
+NS_IMPL_ISUPPORTS(FakeChannel, nsIChannel, nsIAuthPromptCallback, nsIRequest,
+ nsIInterfaceRequestor, nsILoadContext);
+
+mozilla::ipc::IPCResult BrowserParent::RecvAsyncAuthPrompt(
+ const nsCString& aUri, const nsString& aRealm,
+ const uint64_t& aCallbackId) {
+ nsCOMPtr<nsIAuthPrompt2> authPrompt;
+ GetAuthPrompt(nsIAuthPromptProvider::PROMPT_NORMAL,
+ NS_GET_IID(nsIAuthPrompt2), getter_AddRefs(authPrompt));
+ RefPtr<FakeChannel> channel =
+ new FakeChannel(aUri, aCallbackId, mFrameElement);
+ uint32_t promptFlags = nsIAuthInformation::AUTH_HOST;
+
+ RefPtr<nsAuthInformationHolder> holder =
+ new nsAuthInformationHolder(promptFlags, aRealm, ""_ns);
+
+ uint32_t level = nsIAuthPrompt2::LEVEL_NONE;
+ nsCOMPtr<nsICancelable> dummy;
+ nsresult rv = authPrompt->AsyncPromptAuth(channel, channel, nullptr, level,
+ holder, getter_AddRefs(dummy));
+
+ if (NS_FAILED(rv)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvInvokeDragSession(
+ nsTArray<IPCDataTransfer>&& aTransfers, const uint32_t& aAction,
+ Maybe<Shmem>&& aVisualDnDData, const uint32_t& aStride,
+ const gfx::SurfaceFormat& aFormat, const LayoutDeviceIntRect& aDragRect,
+ nsIPrincipal* aPrincipal, nsIContentSecurityPolicy* aCsp,
+ const CookieJarSettingsArgs& aCookieJarSettingsArgs) {
+ PresShell* presShell = mFrameElement->OwnerDoc()->GetPresShell();
+ if (!presShell) {
+ Unused << Manager()->SendEndDragSession(true, true, LayoutDeviceIntPoint(),
+ 0);
+ // Continue sending input events with input priority when stopping the dnd
+ // session.
+ Manager()->SetInputPriorityEventEnabled(true);
+ return IPC_OK();
+ }
+
+ nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
+ net::CookieJarSettings::Deserialize(aCookieJarSettingsArgs,
+ getter_AddRefs(cookieJarSettings));
+
+ RefPtr<RemoteDragStartData> dragStartData =
+ new RemoteDragStartData(this, std::move(aTransfers), aDragRect,
+ aPrincipal, aCsp, cookieJarSettings);
+
+ if (!aVisualDnDData.isNothing() && aVisualDnDData.ref().IsReadable() &&
+ aVisualDnDData.ref().Size<char>() >= aDragRect.height * aStride) {
+ dragStartData->SetVisualization(gfx::CreateDataSourceSurfaceFromData(
+ gfx::IntSize(aDragRect.width, aDragRect.height), aFormat,
+ aVisualDnDData.ref().get<uint8_t>(), aStride));
+ }
+
+ nsCOMPtr<nsIDragService> dragService =
+ do_GetService("@mozilla.org/widget/dragservice;1");
+ if (dragService) {
+ dragService->MaybeAddChildProcess(Manager());
+ }
+
+ presShell->GetPresContext()
+ ->EventStateManager()
+ ->BeginTrackingRemoteDragGesture(mFrameElement, dragStartData);
+
+ if (aVisualDnDData.isSome()) {
+ Unused << DeallocShmem(aVisualDnDData.ref());
+ }
+
+ return IPC_OK();
+}
+
+bool BrowserParent::AsyncPanZoomEnabled() const {
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ return widget && widget->AsyncPanZoomEnabled();
+}
+
+void BrowserParent::StartPersistence(
+ CanonicalBrowsingContext* aContext,
+ nsIWebBrowserPersistDocumentReceiver* aRecv, ErrorResult& aRv) {
+ auto* actor = new WebBrowserPersistDocumentParent();
+ actor->SetOnReady(aRecv);
+ bool ok = Manager()->SendPWebBrowserPersistDocumentConstructor(actor, this,
+ aContext);
+ if (!ok) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ }
+ // (The actor will be destroyed on constructor failure.)
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvLookUpDictionary(
+ const nsString& aText, nsTArray<FontRange>&& aFontRangeArray,
+ const bool& aIsVertical, const LayoutDeviceIntPoint& aPoint) {
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (!widget) {
+ return IPC_OK();
+ }
+
+ widget->LookUpDictionary(aText, aFontRangeArray, aIsVertical,
+ TransformChildToParent(aPoint));
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvShowCanvasPermissionPrompt(
+ const nsCString& aOrigin, const bool& aHideDoorHanger) {
+ nsCOMPtr<nsIBrowser> browser =
+ mFrameElement ? mFrameElement->AsBrowser() : nullptr;
+ if (!browser) {
+ // If the tab is being closed, the browser may not be available.
+ // In this case we can ignore the request.
+ return IPC_OK();
+ }
+ nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+ if (!os) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ nsresult rv = os->NotifyObservers(
+ browser,
+ aHideDoorHanger ? "canvas-permissions-prompt-hide-doorhanger"
+ : "canvas-permissions-prompt",
+ NS_ConvertUTF8toUTF16(aOrigin).get());
+ if (NS_FAILED(rv)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvVisitURI(nsIURI* aURI,
+ nsIURI* aLastVisitedURI,
+ const uint32_t& aFlags) {
+ if (!aURI) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ RefPtr<nsIWidget> widget = GetWidget();
+ if (NS_WARN_IF(!widget)) {
+ return IPC_OK();
+ }
+ nsCOMPtr<IHistory> history = services::GetHistory();
+ if (history) {
+ Unused << history->VisitURI(widget, aURI, aLastVisitedURI, aFlags);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvQueryVisitedState(
+ const nsTArray<RefPtr<nsIURI>>&& aURIs) {
+#ifdef MOZ_ANDROID_HISTORY
+ nsCOMPtr<IHistory> history = services::GetHistory();
+ if (NS_WARN_IF(!history)) {
+ return IPC_OK();
+ }
+ RefPtr<nsIWidget> widget = GetWidget();
+ if (NS_WARN_IF(!widget)) {
+ return IPC_OK();
+ }
+
+ for (size_t i = 0; i < aURIs.Length(); ++i) {
+ if (!aURIs[i]) {
+ return IPC_FAIL(this, "Received null URI");
+ }
+ }
+
+ GeckoViewHistory* gvHistory = static_cast<GeckoViewHistory*>(history.get());
+ gvHistory->QueryVisitedState(widget, std::move(aURIs));
+
+ return IPC_OK();
+#else
+ return IPC_FAIL(this, "QueryVisitedState is Android-only");
+#endif
+}
+
+void BrowserParent::LiveResizeStarted() { SuppressDisplayport(true); }
+
+void BrowserParent::LiveResizeStopped() { SuppressDisplayport(false); }
+
+void BrowserParent::SetBrowserBridgeParent(BrowserBridgeParent* aBrowser) {
+ // We should either be clearing out our reference to a browser bridge, or not
+ // have either a browser bridge, browser host, or owner content yet.
+ MOZ_ASSERT(!aBrowser ||
+ (!mBrowserBridgeParent && !mBrowserHost && !mFrameElement));
+ mBrowserBridgeParent = aBrowser;
+}
+
+void BrowserParent::SetBrowserHost(BrowserHost* aBrowser) {
+ // We should either be clearing out our reference to a browser host, or not
+ // have either a browser bridge, browser host, or owner content yet.
+ MOZ_ASSERT(!aBrowser ||
+ (!mBrowserBridgeParent && !mBrowserHost && !mFrameElement));
+ mBrowserHost = aBrowser;
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvSetSystemFont(
+ const nsCString& aFontName) {
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (widget) {
+ widget->SetSystemFont(aFontName);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvGetSystemFont(nsCString* aFontName) {
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (widget) {
+ widget->GetSystemFont(*aFontName);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvMaybeFireEmbedderLoadEvents(
+ EmbedderElementEventType aFireEventAtEmbeddingElement) {
+ BrowserBridgeParent* bridge = GetBrowserBridgeParent();
+ if (!bridge) {
+ NS_WARNING("Received `load` event on unbridged BrowserParent!");
+ return IPC_OK();
+ }
+
+ Unused << bridge->SendMaybeFireEmbedderLoadEvents(
+ aFireEventAtEmbeddingElement);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvScrollRectIntoView(
+ const nsRect& aRect, const ScrollAxis& aVertical,
+ const ScrollAxis& aHorizontal, const ScrollFlags& aScrollFlags,
+ const int32_t& aAppUnitsPerDevPixel) {
+ BrowserBridgeParent* bridge = GetBrowserBridgeParent();
+ if (!bridge || !bridge->CanSend()) {
+ return IPC_OK();
+ }
+
+ Unused << bridge->SendScrollRectIntoView(aRect, aVertical, aHorizontal,
+ aScrollFlags, aAppUnitsPerDevPixel);
+ return IPC_OK();
+}
+
+NS_IMETHODIMP
+FakeChannel::OnAuthAvailable(nsISupports* aContext,
+ nsIAuthInformation* aAuthInfo) {
+ nsAuthInformationHolder* holder =
+ static_cast<nsAuthInformationHolder*>(aAuthInfo);
+
+ if (!net::gNeckoChild->SendOnAuthAvailable(
+ mCallbackId, holder->User(), holder->Password(), holder->Domain())) {
+ return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+FakeChannel::OnAuthCancelled(nsISupports* aContext, bool userCancel) {
+ if (!net::gNeckoChild->SendOnAuthCancelled(mCallbackId, userCancel)) {
+ return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvIsWindowSupportingProtectedMedia(
+ const uint64_t& aOuterWindowID,
+ IsWindowSupportingProtectedMediaResolver&& aResolve) {
+#ifdef XP_WIN
+ bool isFxrWindow =
+ FxRWindowManager::GetInstance()->IsFxRWindow(aOuterWindowID);
+ aResolve(!isFxrWindow);
+#else
+ MOZ_CRASH("Should only be called on Windows");
+#endif
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvIsWindowSupportingWebVR(
+ const uint64_t& aOuterWindowID,
+ IsWindowSupportingWebVRResolver&& aResolve) {
+#ifdef XP_WIN
+ bool isFxrWindow =
+ FxRWindowManager::GetInstance()->IsFxRWindow(aOuterWindowID);
+ aResolve(!isFxrWindow);
+#else
+ aResolve(true);
+#endif
+
+ return IPC_OK();
+}
+
+bool BrowserParent::SetPointerLock() {
+ if (sPointerLockedRemoteTarget) {
+ return sPointerLockedRemoteTarget == this;
+ }
+
+ sPointerLockedRemoteTarget = this;
+ return true;
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvRequestPointerLock(
+ RequestPointerLockResolver&& aResolve) {
+ nsCString error;
+ if (!SetPointerLock()) {
+ error = "PointerLockDeniedInUse";
+ } else {
+ PointerEventHandler::ReleaseAllPointerCaptureRemoteTarget();
+ }
+ aResolve(error);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvReleasePointerLock() {
+ MOZ_ASSERT_IF(sPointerLockedRemoteTarget, sPointerLockedRemoteTarget == this);
+ UnsetPointerLockedRemoteTarget(this);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvRequestPointerCapture(
+ const uint32_t& aPointerId, RequestPointerCaptureResolver&& aResolve) {
+ aResolve(
+ PointerEventHandler::SetPointerCaptureRemoteTarget(aPointerId, this));
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult BrowserParent::RecvReleasePointerCapture(
+ const uint32_t& aPointerId) {
+ PointerEventHandler::ReleasePointerCaptureRemoteTarget(aPointerId);
+ return IPC_OK();
+}
+
+} // namespace mozilla::dom